diff --git a/.github/workflows/cd-subgraph.yaml b/.github/workflows/cd-subgraph.yaml
index 3f35a3a281..8e1be41306 100644
--- a/.github/workflows/cd-subgraph.yaml
+++ b/.github/workflows/cd-subgraph.yaml
@@ -1,13 +1,11 @@
name: Subgraph deployment
on:
- push:
- branches:
- - main
- paths:
- - packages/sdk/typescript/subgraph/**
- - .github/workflows/cd-subgraph.yaml
workflow_dispatch:
+ inputs:
+ label:
+ description: 'New version label'
+ required: true
jobs:
subgraph:
@@ -16,56 +14,42 @@ jobs:
strategy:
matrix:
network:
- - name: matic
- graph: polygon-v2
- - name: goerli
- graph: goerli-v2
- - name: moonbeam
- graph: moonbeam-v2
- - name: bsc
- graph: bsc-v2
- - name: chapel
- graph: bsctest-v2
- - name: mumbai
- graph: mumbai-v2
- - name: mbase
- graph: moonbase-alpha-v2
- - name: mainnet
- graph: mainnet-v2
- - name: fuji
- graph: fuji-v2
+ - name: amoy
- name: avalanche
- graph: avalanche-v2
- - name: celo
- graph: celo
+ - name: bsc-testnet
+ - name: bsc
- name: celo-alfajores
- graph: celo-alfajores
- - name : xlayer-testnet
- graph: xlayer-testnet
+ - name: celo
+ - name: ethereum
+ - name: fuji
+ - name: moonbase-alpha
+ - name: moonbeam
+ - name: polygon
+ - name: sepolia
+ - name: xlayer-testnet
- name: xlayer
- graph: xlayer
fail-fast: true
max-parallel: 3
steps:
- uses: actions/checkout@v4
- - run: yarn --ignore-scripts
+ - run: npm install --global yarn && yarn --ignore-scripts
name: Install dependencies
- run: yarn build
name: Build core package
working-directory: ./packages/core
- run: yarn global add @graphprotocol/graph-cli
name: Install Graph CLI
- - run: graph auth --product hosted-service ${API_KEY}
+ - run: graph auth --studio ${API_KEY}
name: Authenticate Graph CLI
env:
API_KEY: ${{ secrets.HP_GRAPH_API_KEY }}
- - run: yarn generate
- name: Generate Subgraph
+ - run: yarn generate && yarn build
+ name: Generate and build Subgraph
working-directory: ./packages/sdk/typescript/subgraph
env:
- NETWORK: ${{ matrix.network.graph }}
- - run: graph deploy --product hosted-service humanprotocol/${NETWORK}
+ NETWORK: ${{ matrix.network.name }}
+ - run: graph deploy --studio ${NETWORK} -l ${{ github.event.inputs.label }}
name: Deploy Subgraph
working-directory: ./packages/sdk/typescript/subgraph
env:
- NETWORK: ${{ matrix.network.graph }}
+ NETWORK: ${{ matrix.network.name }}
diff --git a/.github/workflows/ci-dependency-review.yaml b/.github/workflows/ci-dependency-review.yaml
index 58e2a98d57..65029f2431 100644
--- a/.github/workflows/ci-dependency-review.yaml
+++ b/.github/workflows/ci-dependency-review.yaml
@@ -11,4 +11,4 @@ jobs:
- name: "Checkout Repository"
uses: actions/checkout@v4.1.1
- name: "Dependency Review"
- uses: actions/dependency-review-action@v4.3.2
+ uses: actions/dependency-review-action@v4.3.4
diff --git a/.github/workflows/ci-test-core.yaml b/.github/workflows/ci-test-core.yaml
index d4e44d99e1..11c85a8274 100644
--- a/.github/workflows/ci-test-core.yaml
+++ b/.github/workflows/ci-test-core.yaml
@@ -17,5 +17,5 @@ jobs:
- uses: actions/checkout@v4
- run: npm install --global yarn && yarn --ignore-scripts
name: Install dependencies
- - run: yarn core:test
+ - run: yarn workspace @human-protocol/core test
name: Run protocol test
diff --git a/.github/workflows/ci-test-dashboard-ui.yaml b/.github/workflows/ci-test-dashboard-ui.yaml
index 7fa612d636..e13fde2561 100644
--- a/.github/workflows/ci-test-dashboard-ui.yaml
+++ b/.github/workflows/ci-test-dashboard-ui.yaml
@@ -20,5 +20,5 @@ jobs:
- uses: actions/checkout@v4
- run: npm install --global yarn && yarn
name: Install dependencies
- - run: yarn dashboard-ui:test
+ - run: yarn workspace @human-protocol/dashboard-ui test
name: Run dashboard-ui test
diff --git a/.github/workflows/ci-test-faucet-server.yaml b/.github/workflows/ci-test-faucet-server.yaml
index 0151e4646b..7a15bdd29a 100644
--- a/.github/workflows/ci-test-faucet-server.yaml
+++ b/.github/workflows/ci-test-faucet-server.yaml
@@ -22,5 +22,5 @@ jobs:
- run: cp .env.example .env
name: Create .env file
working-directory: packages/apps/faucet-server
- - run: yarn faucet-server:test
+ - run: yarn workspace @human-protocol/faucet-server test
name: Run faucet-server test
diff --git a/.github/workflows/ci-test-fortune-v3.yaml b/.github/workflows/ci-test-fortune-v3.yaml
deleted file mode 100644
index f281777048..0000000000
--- a/.github/workflows/ci-test-fortune-v3.yaml
+++ /dev/null
@@ -1,23 +0,0 @@
-name: Fortune V3 check
-
-on:
- push:
- branches:
- - 'main'
- pull_request:
- paths:
- - 'packages/core/**'
- - 'packages/sdk/typescript/human-protocol-sdk/**'
- - 'packages/app/fortune/**'
- workflow_dispatch:
-
-jobs:
- fortune-test:
- name: Fortune V3 Test
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v4
- - run: npm install --global yarn && yarn
- name: Install dependencies
- - run: yarn fortune-v3:test
- name: Run fortune V3 test
diff --git a/.github/workflows/ci-test-fortune.yaml b/.github/workflows/ci-test-fortune.yaml
new file mode 100644
index 0000000000..415416116a
--- /dev/null
+++ b/.github/workflows/ci-test-fortune.yaml
@@ -0,0 +1,32 @@
+name: Fortune check
+
+on:
+ push:
+ branches:
+ - 'main'
+ pull_request:
+ paths:
+ - 'packages/core/**'
+ - 'packages/sdk/typescript/human-protocol-sdk/**'
+ - 'packages/apps/fortune/**'
+ workflow_dispatch:
+
+jobs:
+ fortune-exchange-oracle-test:
+ name: Fortune Exchange Oracle Tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - run: npm install --global yarn && yarn
+ name: Install dependencies
+ - run: yarn workspace @human-protocol/fortune-exchange-oracle-server test
+ name: Run Exchange Oracle tests
+ fortune-recording-oracle-test:
+ name: Fortune Recording Oracle Tests
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - run: npm install --global yarn && yarn
+ name: Install dependencies
+ - run: yarn workspace @human-protocol/fortune-recording-oracle test
+ name: Run Recording Oracle tests
diff --git a/.github/workflows/ci-test-human-app.yaml b/.github/workflows/ci-test-human-app.yaml
index 505b1f8c98..126e507d2f 100644
--- a/.github/workflows/ci-test-human-app.yaml
+++ b/.github/workflows/ci-test-human-app.yaml
@@ -3,12 +3,12 @@ name: Human App Check
on:
push:
branches:
- - "main"
+ - 'main'
pull_request:
paths:
- - "packages/core/**"
- - "packages/sdk/typescript/human-protocol-sdk/**"
- - "packages/apps/human-app/**"
+ - 'packages/core/**'
+ - 'packages/sdk/typescript/human-protocol-sdk/**'
+ - 'packages/apps/human-app/**'
workflow_dispatch:
jobs:
@@ -19,5 +19,5 @@ jobs:
- uses: actions/checkout@v4
- run: npm install --global yarn && yarn
name: Install dependencies
- - run: yarn human-app-server:test
+ - run: yarn workspace @human-protocol/human-app-server test
name: Run Job Human App unit tests
diff --git a/.github/workflows/ci-test-job-launcher.yaml b/.github/workflows/ci-test-job-launcher.yaml
index 0910c1aaad..a7c6a19899 100644
--- a/.github/workflows/ci-test-job-launcher.yaml
+++ b/.github/workflows/ci-test-job-launcher.yaml
@@ -3,12 +3,12 @@ name: Job Launcher Check
on:
push:
branches:
- - "main"
+ - 'main'
pull_request:
paths:
- - "packages/core/**"
- - "packages/sdk/typescript/human-protocol-sdk/**"
- - "packages/apps/job-launcher/**"
+ - 'packages/core/**'
+ - 'packages/sdk/typescript/human-protocol-sdk/**'
+ - 'packages/apps/job-launcher/**'
workflow_dispatch:
jobs:
@@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v4
- run: npm install --global yarn && yarn
name: Install dependencies
- - run: yarn job-launcher-client:test
+ - run: yarn workspace @human-protocol/job-launcher-client test
name: Run Job Launcher Client test
job-launcher-server-test:
name: Job Launcher Server Test
@@ -28,5 +28,5 @@ jobs:
- uses: actions/checkout@v4
- run: npm install --global yarn && yarn
name: Install dependencies
- - run: yarn job-launcher-server:test
+ - run: yarn workspace @human-protocol/job-launcher-server test
name: Run Job Launcher Server test
diff --git a/.github/workflows/ci-test-node-sdk.yaml b/.github/workflows/ci-test-node-sdk.yaml
index ef8412023d..e51bd1127b 100644
--- a/.github/workflows/ci-test-node-sdk.yaml
+++ b/.github/workflows/ci-test-node-sdk.yaml
@@ -21,5 +21,5 @@ jobs:
- run: yarn build
name: Build core package
working-directory: ./packages/core
- - run: yarn sdk:test
+ - run: yarn workspace @human-protocol/sdk test
name: Run Node.js SDK test
diff --git a/.github/workflows/ci-test-reputation-oracle.yaml b/.github/workflows/ci-test-reputation-oracle.yaml
index 7fd5466824..593f21ed09 100644
--- a/.github/workflows/ci-test-reputation-oracle.yaml
+++ b/.github/workflows/ci-test-reputation-oracle.yaml
@@ -3,12 +3,12 @@ name: Reputation Oracle Check
on:
push:
branches:
- - "main"
+ - 'main'
pull_request:
paths:
- - "packages/core/**"
- - "packages/sdk/typescript/human-protocol-sdk/**"
- - "packages/apps/reputation-oracle/**"
+ - 'packages/core/**'
+ - 'packages/sdk/typescript/human-protocol-sdk/**'
+ - 'packages/apps/reputation-oracle/**'
workflow_dispatch:
jobs:
@@ -19,5 +19,5 @@ jobs:
- uses: actions/checkout@v4
- run: npm install --global yarn && yarn
name: Install dependencies
- - run: yarn reputation-oracle:test
+ - run: yarn workspace @human-protocol/reputation-oracle test
name: Run reputation oracle test
diff --git a/.github/workflows/ci-test-subgraph.yaml b/.github/workflows/ci-test-subgraph.yaml
index b7285f2944..c3146e96d4 100644
--- a/.github/workflows/ci-test-subgraph.yaml
+++ b/.github/workflows/ci-test-subgraph.yaml
@@ -18,5 +18,5 @@ jobs:
- uses: actions/checkout@v4
- run: npm install --global yarn && yarn
name: Install dependencies
- - run: yarn subgraph:test
+ - run: yarn workspace @human-protocol/subgraph test
name: Run subgraph test
diff --git a/docs/sdk/SUMMARY.md b/docs/sdk/SUMMARY.md
index bfe2659f38..4e62141d34 100644
--- a/docs/sdk/SUMMARY.md
+++ b/docs/sdk/SUMMARY.md
@@ -1,6 +1,6 @@
# Table of contents
-## Typescript SDK
+## Typescript SDK
- [Encryption](typescript/encryption/README.md)
- [Encryption](typescript/encryption/classes/Encryption.md)
@@ -10,6 +10,7 @@
- [EscrowUtils](typescript/escrow/classes/EscrowUtils.md)
- [KVStore](typescript/kvstore/README.md)
- [KVStoreClient](typescript/kvstore/classes/KVStoreClient.md)
+ - [KVStoreUtils](typescript/kvstore/classes/KVStoreUtils.md)
- [Staking](typescript/staking/README.md)
- [StakingClient](typescript/staking/classes/StakingClient.md)
- [Operator](typescript/operator/README.md)
@@ -36,6 +37,7 @@
- [escrow_utils](python/human_protocol_sdk.escrow.escrow_utils.md)
- [kvstore](python/human_protocol_sdk.kvstore.md)
- [kvstore_client](python/human_protocol_sdk.kvstore.kvstore_client.md)
+ - [kvstore_utils](python/human_protocol_sdk.kvstore.kvstore_utils.md)
- [staking](python/human_protocol_sdk.staking.md)
- [staking_client](python/human_protocol_sdk.staking.staking_client.md)
- [staking_utils](python/human_protocol_sdk.staking.staking_utils.md)
@@ -54,4 +56,4 @@
---
-- [CHANGELOG](./changelog.md)
+- [CHANGELOG](changelog.md)
diff --git a/docs/sdk/python/human_protocol_sdk.constants.md b/docs/sdk/python/human_protocol_sdk.constants.md
index 9e586b6829..9169b4ce20 100644
--- a/docs/sdk/python/human_protocol_sdk.constants.md
+++ b/docs/sdk/python/human_protocol_sdk.constants.md
@@ -60,6 +60,16 @@ Enum for KVStore keys
#### webhook_url *= 'webhook_url'*
+### *class* human_protocol_sdk.constants.OrderDirection(value)
+
+Bases: `Enum`
+
+Enum for chain IDs.
+
+#### ASC *= 'asc'*
+
+#### DESC *= 'desc'*
+
### *class* human_protocol_sdk.constants.Role(value)
Bases: `Enum`
diff --git a/docs/sdk/python/human_protocol_sdk.escrow.escrow_utils.md b/docs/sdk/python/human_protocol_sdk.escrow.escrow_utils.md
index 2601bb65f3..c9794f2b4e 100644
--- a/docs/sdk/python/human_protocol_sdk.escrow.escrow_utils.md
+++ b/docs/sdk/python/human_protocol_sdk.escrow.escrow_utils.md
@@ -84,7 +84,7 @@ Returns the escrow for a given address.
)
```
-#### *static* get_escrows(filter=)
+#### *static* get_escrows(filter)
Get an array of escrow addresses based on the specified filter parameters.
@@ -110,3 +110,56 @@ Get an array of escrow addresses based on the specified filter parameters.
)
)
```
+
+#### *static* get_status_events(chain_id, statuses=None, date_from=None, date_to=None, launcher=None, first=10, skip=0, order_direction=OrderDirection.DESC)
+
+Retrieve status events for specified networks and statuses within a date range.
+
+* **Parameters:**
+ * **chain_id** ([`ChainId`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.ChainId)) – Network to request data.
+ * **(****Optional****[****List****[****Status****]****]****)** (*statuses*) – List of statuses to filter by.
+ * **(****Optional****[****datetime****]****)** (*date_to*) – Start date for the query range.
+ * **(****Optional****[****datetime****]****)** – End date for the query range.
+ * **(****Optional****[****str****]****)** (*launcher*) – Address of the launcher to filter by.
+ * **(****int****)** (*skip*) – Number of items per page.
+ * **(****int****)** – Page number to retrieve.
+ * **(****OrderDirection****)** (*order_direction*) – Order of results, “asc” or “desc”.
+* **Return List[StatusEvent]:**
+ List of status events matching the query parameters.
+* **Raises:**
+ [**EscrowClientError**](human_protocol_sdk.escrow.escrow_client.md#human_protocol_sdk.escrow.escrow_client.EscrowClientError) – If an unsupported chain ID or invalid launcher address is provided.
+* **Example:**
+ ```python
+ from datetime import datetime
+ from human_protocol_sdk.constants import ChainId, Status
+ from human_protocol_sdk.escrow import EscrowUtils
+
+ print(
+ EscrowUtils.get_status_events(
+ networks=[ChainId.POLYGON_AMOY, ChainId.ETHEREUM],
+ statuses=[Status.Pending, Status.Paid],
+ date_from=datetime(2023, 1, 1),
+ date_to=datetime(2023, 12, 31),
+ launcher="0x1234567890abcdef1234567890abcdef12345678",
+ first=20,
+ skip=0,
+ order_direction=OrderDirection.DESC
+ )
+ )
+ ```
+* **Return type:**
+ `List`[[`StatusEvent`](#human_protocol_sdk.escrow.escrow_utils.StatusEvent)]
+
+### *class* human_protocol_sdk.escrow.escrow_utils.StatusEvent(timestamp, status, chain_id, escrow_address)
+
+Bases: `object`
+
+Initializes a StatusEvent instance.
+
+* **Parameters:**
+ * **timestamp** (`int`) – The timestamp of the event.
+ * **status** (`str`) – The status of the escrow.
+ * **chain_id** ([`ChainId`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.ChainId)) – The chain identifier where the event occurred.
+ * **escrow_address** (`str`) – The address of the escrow.
+
+#### \_\_init_\_(timestamp, status, chain_id, escrow_address)
diff --git a/docs/sdk/python/human_protocol_sdk.escrow.md b/docs/sdk/python/human_protocol_sdk.escrow.md
index d5f4da28c0..b7cfbd1674 100644
--- a/docs/sdk/python/human_protocol_sdk.escrow.md
+++ b/docs/sdk/python/human_protocol_sdk.escrow.md
@@ -45,3 +45,6 @@ obtain information from both the contracts and subgraph.
* [`EscrowUtils`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.EscrowUtils)
* [`EscrowUtils.get_escrow()`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.EscrowUtils.get_escrow)
* [`EscrowUtils.get_escrows()`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.EscrowUtils.get_escrows)
+ * [`EscrowUtils.get_status_events()`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.EscrowUtils.get_status_events)
+ * [`StatusEvent`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.StatusEvent)
+ * [`StatusEvent.__init__()`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.StatusEvent.__init__)
diff --git a/docs/sdk/python/human_protocol_sdk.filter.md b/docs/sdk/python/human_protocol_sdk.filter.md
index c5e7fadf1c..3063e409b9 100644
--- a/docs/sdk/python/human_protocol_sdk.filter.md
+++ b/docs/sdk/python/human_protocol_sdk.filter.md
@@ -1,17 +1,17 @@
# human_protocol_sdk.filter module
-### *class* human_protocol_sdk.filter.EscrowFilter(networks, launcher=None, reputation_oracle=None, recording_oracle=None, exchange_oracle=None, job_requester_id=None, status=None, date_from=None, date_to=None)
+### *class* human_protocol_sdk.filter.EscrowFilter(chain_id, launcher=None, reputation_oracle=None, recording_oracle=None, exchange_oracle=None, job_requester_id=None, status=None, date_from=None, date_to=None, first=10, skip=0, order_direction=OrderDirection.DESC)
Bases: `object`
A class used to filter escrow requests.
-#### \_\_init_\_(networks, launcher=None, reputation_oracle=None, recording_oracle=None, exchange_oracle=None, job_requester_id=None, status=None, date_from=None, date_to=None)
+#### \_\_init_\_(chain_id, launcher=None, reputation_oracle=None, recording_oracle=None, exchange_oracle=None, job_requester_id=None, status=None, date_from=None, date_to=None, first=10, skip=0, order_direction=OrderDirection.DESC)
Initializes a EscrowFilter instance.
* **Parameters:**
- * **networks** (`List`[[`ChainId`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.ChainId)]) – Networks to request data
+ * **chain_id** ([`ChainId`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.ChainId)) – Network to request data
* **launcher** (`Optional`[`str`]) – Launcher address
* **reputation_oracle** (`Optional`[`str`]) – Reputation oracle address
* **recording_oracle** (`Optional`[`str`]) – Recording oracle address
@@ -20,6 +20,9 @@ Initializes a EscrowFilter instance.
* **status** (`Optional`[[`Status`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.Status)]) – Escrow status
* **date_from** (`Optional`[`datetime`]) – Created from date
* **date_to** (`Optional`[`datetime`]) – Created to date
+ * **first** (`int`) – Number of items per page
+ * **skip** (`int`) – Page number to retrieve
+ * **order_direction** ([`OrderDirection`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.OrderDirection)) – Order of results, “asc” or “desc”
### *exception* human_protocol_sdk.filter.FilterError
@@ -43,23 +46,26 @@ Initializes a PayoutFilter instance.
* **date_from** (`Optional`[`datetime`]) – Created from date
* **date_to** (`Optional`[`datetime`]) – Created to date
-### *class* human_protocol_sdk.filter.TransactionFilter(networks, from_address=None, to_address=None, start_date=None, end_date=None, start_block=None, end_block=None)
+### *class* human_protocol_sdk.filter.TransactionFilter(chain_id, from_address=None, to_address=None, start_date=None, end_date=None, start_block=None, end_block=None, first=10, skip=0, order_direction=OrderDirection.DESC)
Bases: `object`
A class used to filter transactions.
-#### \_\_init_\_(networks, from_address=None, to_address=None, start_date=None, end_date=None, start_block=None, end_block=None)
+#### \_\_init_\_(chain_id, from_address=None, to_address=None, start_date=None, end_date=None, start_block=None, end_block=None, first=10, skip=0, order_direction=OrderDirection.DESC)
Initializes a TransactionsFilter instance.
* **Parameters:**
- * **networks** (`List`[[`ChainId`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.ChainId)]) – List of chain IDs to filter transactions from
+ * **chain_id** ([`ChainId`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.ChainId)) – Chain ID to filter transactions from
* **from_address** (`Optional`[`str`]) – Sender address
* **to_address** (`Optional`[`str`]) – Receiver address
* **start_date** (`Optional`[`datetime`]) – Start date for filtering transactions
* **end_date** (`Optional`[`datetime`]) – End date for filtering transactions
* **start_block** (`Optional`[`int`]) – Start block number for filtering transactions
* **end_block** (`Optional`[`int`]) – End block number for filtering transactions
+ * **first** (`int`) – Number of items per page
+ * **skip** (`int`) – Page number to retrieve
+ * **order** – Order of results, “asc” or “desc”
* **Raises:**
**ValueError** – If start_date is after end_date
diff --git a/docs/sdk/python/human_protocol_sdk.md b/docs/sdk/python/human_protocol_sdk.md
index b779d78361..5128735f58 100644
--- a/docs/sdk/python/human_protocol_sdk.md
+++ b/docs/sdk/python/human_protocol_sdk.md
@@ -45,6 +45,7 @@
* [Module](human_protocol_sdk.escrow.escrow_utils.md#module)
* [`EscrowData`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.EscrowData)
* [`EscrowUtils`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.EscrowUtils)
+ * [`StatusEvent`](human_protocol_sdk.escrow.escrow_utils.md#human_protocol_sdk.escrow.escrow_utils.StatusEvent)
* [human_protocol_sdk.kvstore package](human_protocol_sdk.kvstore.md)
* [Submodules](human_protocol_sdk.kvstore.md#submodules)
* [human_protocol_sdk.kvstore.kvstore_client module](human_protocol_sdk.kvstore.kvstore_client.md)
@@ -82,6 +83,7 @@
* [`DailyWorkerData`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.DailyWorkerData)
* [`EscrowStatistics`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.EscrowStatistics)
* [`HMTHolder`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTHolder)
+ * [`HMTHoldersParam`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTHoldersParam)
* [`HMTStatistics`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTStatistics)
* [`PaymentStatistics`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.PaymentStatistics)
* [`StatisticsClient`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient)
@@ -129,6 +131,9 @@
* [`KVStoreKeys.role`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.KVStoreKeys.role)
* [`KVStoreKeys.url`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.KVStoreKeys.url)
* [`KVStoreKeys.webhook_url`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.KVStoreKeys.webhook_url)
+ * [`OrderDirection`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.OrderDirection)
+ * [`OrderDirection.ASC`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.OrderDirection.ASC)
+ * [`OrderDirection.DESC`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.OrderDirection.DESC)
* [`Role`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.Role)
* [`Role.exchange_oracle`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.Role.exchange_oracle)
* [`Role.job_launcher`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.Role.job_launcher)
diff --git a/docs/sdk/python/human_protocol_sdk.statistics.md b/docs/sdk/python/human_protocol_sdk.statistics.md
index 19354040e5..a4873551f5 100644
--- a/docs/sdk/python/human_protocol_sdk.statistics.md
+++ b/docs/sdk/python/human_protocol_sdk.statistics.md
@@ -19,6 +19,8 @@ This module allows to read statistical data from the subgraph.
* [`EscrowStatistics.__init__()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.EscrowStatistics.__init__)
* [`HMTHolder`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTHolder)
* [`HMTHolder.__init__()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTHolder.__init__)
+ * [`HMTHoldersParam`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTHoldersParam)
+ * [`HMTHoldersParam.__init__()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTHoldersParam.__init__)
* [`HMTStatistics`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTStatistics)
* [`HMTStatistics.__init__()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.HMTStatistics.__init__)
* [`PaymentStatistics`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.PaymentStatistics)
@@ -26,6 +28,7 @@ This module allows to read statistical data from the subgraph.
* [`StatisticsClient`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient)
* [`StatisticsClient.__init__()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient.__init__)
* [`StatisticsClient.get_escrow_statistics()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient.get_escrow_statistics)
+ * [`StatisticsClient.get_hmt_holders()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient.get_hmt_holders)
* [`StatisticsClient.get_hmt_statistics()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient.get_hmt_statistics)
* [`StatisticsClient.get_payment_statistics()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient.get_payment_statistics)
* [`StatisticsClient.get_worker_statistics()`](human_protocol_sdk.statistics.statistics_client.md#human_protocol_sdk.statistics.statistics_client.StatisticsClient.get_worker_statistics)
diff --git a/docs/sdk/python/human_protocol_sdk.statistics.statistics_client.md b/docs/sdk/python/human_protocol_sdk.statistics.statistics_client.md
index 0c2bd26c86..2e01b28857 100644
--- a/docs/sdk/python/human_protocol_sdk.statistics.statistics_client.md
+++ b/docs/sdk/python/human_protocol_sdk.statistics.statistics_client.md
@@ -31,13 +31,13 @@ Initializes a DailyEscrowData instance.
* **escrows_paid** (`int`) – Paid escrows
* **escrows_cancelled** (`int`) – Cancelled escrows
-### *class* human_protocol_sdk.statistics.statistics_client.DailyHMTData(timestamp, total_transaction_amount, total_transaction_count)
+### *class* human_protocol_sdk.statistics.statistics_client.DailyHMTData(timestamp, total_transaction_amount, total_transaction_count, daily_unique_senders, daily_unique_receivers)
Bases: `object`
A class used to specify daily HMT data.
-#### \_\_init_\_(timestamp, total_transaction_amount, total_transaction_count)
+#### \_\_init_\_(timestamp, total_transaction_amount, total_transaction_count, daily_unique_senders, daily_unique_receivers)
Initializes a DailyHMTData instance.
@@ -45,6 +45,8 @@ Initializes a DailyHMTData instance.
* **timestamp** (`datetime`) – Timestamp
* **total_transaction_amount** (`int`) – Total transaction amount
* **total_transaction_count** (`int`) – Total transaction count
+ * **daily_unique_senders** (`int`) – Total unique senders
+ * **daily_unique_receivers** (`int`) – Total unique receivers
### *class* human_protocol_sdk.statistics.statistics_client.DailyPaymentData(timestamp, total_amount_paid, total_count, average_amount_per_worker)
@@ -104,6 +106,20 @@ Initializes a HMTHolder instance.
* **address** (`str`) – Holder address
* **balance** (`int`) – Holder balance
+### *class* human_protocol_sdk.statistics.statistics_client.HMTHoldersParam(address=None, order_direction='asc')
+
+Bases: `object`
+
+A class used to specify parameters for querying HMT holders.
+
+#### \_\_init_\_(address=None, order_direction='asc')
+
+Initializes a HMTHoldersParam instance.
+
+* **Parameters:**
+ * **address** (`Optional`[`str`]) – Filter by holder’s address
+ * **order_direction** (`str`) – Optional. Direction of sorting (‘asc’ for ascending, ‘desc’ for descending)
+
### *class* human_protocol_sdk.statistics.statistics_client.HMTStatistics(total_transfer_amount, total_transfer_count, total_holders, holders, daily_hmt_data)
Bases: `object`
@@ -175,6 +191,34 @@ Get escrow statistics data for the given date range.
)
```
+#### get_hmt_holders(param=)
+
+Get HMT holders data with optional filters and ordering.
+
+* **Parameters:**
+ **param** ([`HMTHoldersParam`](#human_protocol_sdk.statistics.statistics_client.HMTHoldersParam)) – Object containing filter and order parameters
+* **Return type:**
+ `List`[[`HMTHolder`](#human_protocol_sdk.statistics.statistics_client.HMTHolder)]
+* **Returns:**
+ List of HMT holders
+* **Example:**
+ ```python
+ from human_protocol_sdk.contants import ChainId
+ from human_protocol_sdk.statistics import StatisticsClient, HMTHoldersParam
+
+ statistics_client = StatisticsClient(ChainId.POLYGON_AMOY)
+
+ print(statistics_client.get_hmt_holders())
+ print(
+ statistics_client.get_hmt_holders(
+ HMTHoldersParam(
+ address="0x123...",
+ order_direction="asc",
+ )
+ )
+ )
+ ```
+
#### get_hmt_statistics(param=)
Get HMT statistics data for the given date range.
diff --git a/docs/sdk/python/human_protocol_sdk.transaction.transaction_utils.md b/docs/sdk/python/human_protocol_sdk.transaction.transaction_utils.md
index f2f50bc9f3..ce1a533e1d 100644
--- a/docs/sdk/python/human_protocol_sdk.transaction.transaction_utils.md
+++ b/docs/sdk/python/human_protocol_sdk.transaction.transaction_utils.md
@@ -23,11 +23,11 @@ print(
## Module
-### *class* human_protocol_sdk.transaction.transaction_utils.TransactionData(chain_id, block, hash, from_address, to_address, timestamp, value, method)
+### *class* human_protocol_sdk.transaction.transaction_utils.TransactionData(chain_id, block, tx_hash, from_address, to_address, timestamp, value, method)
Bases: `object`
-#### \_\_init_\_(chain_id, block, hash, from_address, to_address, timestamp, value, method)
+#### \_\_init_\_(chain_id, block, tx_hash, from_address, to_address, timestamp, value, method)
### *class* human_protocol_sdk.transaction.transaction_utils.TransactionUtils
@@ -77,7 +77,7 @@ Get an array of transactions based on the specified filter parameters.
print(
TransactionUtils.get_transactions(
TransactionFilter(
- networks=[ChainId.POLYGON_AMOY],
+ chain_id=ChainId.POLYGON_AMOY,
from_address="0x1234567890123456789012345678901234567890",
to_address="0x0987654321098765432109876543210987654321",
start_date=datetime.datetime(2023, 5, 8),
diff --git a/docs/sdk/python/index.md b/docs/sdk/python/index.md
index ca5e5e0ea0..9a56acc0c9 100644
--- a/docs/sdk/python/index.md
+++ b/docs/sdk/python/index.md
@@ -44,6 +44,7 @@ pip install human-protocol-sdk[agreement]
* [human_protocol_sdk.constants module](human_protocol_sdk.constants.md)
* [`ChainId`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.ChainId)
* [`KVStoreKeys`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.KVStoreKeys)
+ * [`OrderDirection`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.OrderDirection)
* [`Role`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.Role)
* [`Status`](human_protocol_sdk.constants.md#human_protocol_sdk.constants.Status)
* [human_protocol_sdk.filter module](human_protocol_sdk.filter.md)
diff --git a/docs/sdk/typescript/README.md b/docs/sdk/typescript/README.md
index 6140b1dd9e..43efb8cc51 100644
--- a/docs/sdk/typescript/README.md
+++ b/docs/sdk/typescript/README.md
@@ -2,9 +2,25 @@
***
-# Human Protocol Node.js SDK
-
-Node.js SDK to launch/manage escrows on [Human Protocol](https://www.humanprotocol.org/)
+
+
+
+
+[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
+[circleci-url]: https://circleci.com/gh/nestjs/nest
+
+Human Protocol Node.js SDK
+Node.js SDK to launch/manage escrows on Human Protocol
+
+
+
+
+
+
+
+
+
+
## Installation
@@ -12,83 +28,10 @@ This SDK is available on [NPM](https://www.npmjs.com/package/@human-protocol/sdk
yarn add @human-protocol/sdk
-## Components
-
-- InitClient
-
- **InitClient** has one static function that returns a `Signer` or `Provider` (depending on the passed parameter), as well as a chainId associated with this parameter in an asynchronous way. Used for further passing as a constructor parameter to Web3 dependent modules.
-
-- StorageClient
-
- **StorageClient** is used to upload/download files to the cloud storage with given credentials and params. If credentials are not provided, anonymous access will be used (for downloading files).
-
-- EscrowClient
-
- **EscrowClient** enables to perform actions on Escrow contracts and obtain information from both the contracts and subgraph. Internally, the SDK will use one network or another according to the network ID of the `signerOrProvider`.
-
-- KVStoreClient
-
- **KVStoreClient** enables to perform actions on KVStore contract and obtain information from both the contracts and subgraph. Internally, the SDK will use one network or another according to the network ID of the `signerOrProvider`.
-
-- StakingClient
-
- **StakingClient** enables to perform actions on staking contracts and obtain staking information from both the contracts and subgraph. Internally, the SDK will use one network or another according to the network ID of the `signerOrProvider`.
-
-## Example
-
-```typescript
-const {
- EscrowClient,
- StakingClient,
- NETWORKS,
- ChainId,
-} = require('@human-protocol/sdk');
-const { ethers } = require('ethers');
-
-(async () => {
- // Hardhat Provider
- const provider = new ethers.providers.JsonRpcProvider(
- 'http://127.0.0.1:8545/'
- );
-
- // Load localhost configuration
- const network = NETWORKS[ChainId.LOCALHOST];
-
- const signer = new ethers.Wallet(
- '0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a',
- provider
- );
-
- // Initialize StakingClient
- const stakingClient = new StakingClient({
- signerOrProvider: signer,
- network,
- });
-
- // Stake 10 HMT
- await stakingClient.approveStake(ethers.BigNumber.from(10));
- await stakingClient.stake(ethers.BigNumber.from(10));
+## Documentation
- // Initialize EscrowClient
- const escrowClient = new EscrowClient({
- signerOrProvider: signer,
- network,
- });
+For detailed information about core, please refer to the [Human Protocol Docs](https://sdk.humanprotocol.org/).
- // Create a new escrow, and setup
- const escrowAddress = await escrowClient.createEscrow(network.hmtAddress, [
- signer.address,
- ]);
+## License
- await escrowClient.setup(escrowAddress, {
- recordingOracle: '0x90F79bf6EB2c4f870365E785982E1f101E93b906',
- reputationOracle: '0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65',
- exchangeOracle: '0x6b7E3C31F34cF38d1DFC1D9A8A59482028395809',
- recordingOracleFee: ethers.BigNumber.from(1),
- reputationOracleFee: ethers.BigNumber.from(1),
- exchangeOracleFee: ethers.BigNumber.from(1),
- manifestUrl: 'http://example.com',
- hash: 'test',
- });
-})();
-```
+This project is licensed under the MIT License. See the [LICENSE](https://github.com/humanprotocol/human-protocol/blob/main/LICENSE) file for details.
diff --git a/docs/sdk/typescript/base/classes/BaseEthersClient.md b/docs/sdk/typescript/base/classes/BaseEthersClient.md
index 8a0414357f..1f11c477ad 100644
--- a/docs/sdk/typescript/base/classes/BaseEthersClient.md
+++ b/docs/sdk/typescript/base/classes/BaseEthersClient.md
@@ -38,9 +38,9 @@ The network information required to connect to the contracts
[`BaseEthersClient`](BaseEthersClient.md)
-#### Source
+#### Defined in
-[base.ts:20](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L20)
+[base.ts:20](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L20)
## Properties
@@ -48,9 +48,9 @@ The network information required to connect to the contracts
> **networkData**: `NetworkData`
-#### Source
+#### Defined in
-[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
+[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
***
@@ -58,6 +58,6 @@ The network information required to connect to the contracts
> `protected` **runner**: `ContractRunner`
-#### Source
+#### Defined in
-[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
+[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
diff --git a/docs/sdk/typescript/encryption/classes/Encryption.md b/docs/sdk/typescript/encryption/classes/Encryption.md
index f0abb079b7..995925b3bb 100644
--- a/docs/sdk/typescript/encryption/classes/Encryption.md
+++ b/docs/sdk/typescript/encryption/classes/Encryption.md
@@ -64,19 +64,9 @@ The private key.
[`Encryption`](Encryption.md)
-#### Source
+#### Defined in
-[encryption.ts:53](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L53)
-
-## Properties
-
-### privateKey
-
-> `private` **privateKey**: `PrivateKey`
-
-#### Source
-
-[encryption.ts:46](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L46)
+[encryption.ts:53](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L53)
## Methods
@@ -126,9 +116,9 @@ UYLqAQDfdym4kiUvKO1+REKASt0Gwykndl7hra9txqlUL5DXBQ===Vwgv
const resultMessage = await encription.decrypt('message');
```
-#### Source
+#### Defined in
-[encryption.ts:180](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L180)
+[encryption.ts:180](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L180)
***
@@ -162,9 +152,9 @@ const encription = await Encryption.build(privateKey, passphrase);
const resultMessage = await encription.sign('message');
```
-#### Source
+#### Defined in
-[encryption.ts:217](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L217)
+[encryption.ts:217](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L217)
***
@@ -227,9 +217,9 @@ const publicKeys = [publicKey1, publicKey2];
const resultMessage = await encription.signAndEncrypt('message', publicKeys);
```
-#### Source
+#### Defined in
-[encryption.ts:129](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L129)
+[encryption.ts:129](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L129)
***
@@ -255,6 +245,6 @@ Optional: The passphrase for the private key.
- The Encryption instance.
-#### Source
+#### Defined in
-[encryption.ts:64](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L64)
+[encryption.ts:64](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L64)
diff --git a/docs/sdk/typescript/encryption/classes/EncryptionUtils.md b/docs/sdk/typescript/encryption/classes/EncryptionUtils.md
index e5d455b63d..3ee60e2716 100644
--- a/docs/sdk/typescript/encryption/classes/EncryptionUtils.md
+++ b/docs/sdk/typescript/encryption/classes/EncryptionUtils.md
@@ -95,9 +95,9 @@ const publicKeys = [publicKey1, publicKey2]
const result = await EncriptionUtils.encrypt('message', publicKeys);
```
-#### Source
+#### Defined in
-[encryption.ts:422](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L422)
+[encryption.ts:422](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L422)
***
@@ -117,7 +117,7 @@ Name for the key pair.
Email for the key pair.
-• **passphrase**: `string`= `''`
+• **passphrase**: `string` = `''`
Passphrase to encrypt the private key. Optional.
@@ -150,9 +150,9 @@ const passphrase = 'YOUR_PASSPHRASE';
const result = await EncriptionUtils.generateKeyPair(name, email, passphrase);
```
-#### Source
+#### Defined in
-[encryption.ts:360](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L360)
+[encryption.ts:360](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L360)
***
@@ -182,9 +182,9 @@ import { EncryptionUtils } from '@human-protocol/sdk';
const signedData = await EncriptionUtils.getSignedData('message');
```
-#### Source
+#### Defined in
-[encryption.ts:317](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L317)
+[encryption.ts:317](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L317)
***
@@ -230,9 +230,9 @@ if (isEncrypted) {
}
```
-#### Source
+#### Defined in
-[encryption.ts:471](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L471)
+[encryption.ts:471](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L471)
***
@@ -278,6 +278,6 @@ UYLqAQDfdym4kiUvKO1+REKASt0Gwykndl7hra9txqlUL5DXBQ===Vwgv
const result = await EncriptionUtils.verify('message', publicKey);
```
-#### Source
+#### Defined in
-[encryption.ts:284](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L284)
+[encryption.ts:284](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/encryption.ts#L284)
diff --git a/docs/sdk/typescript/escrow/classes/EscrowClient.md b/docs/sdk/typescript/escrow/classes/EscrowClient.md
index 0f74984e8b..247e140f85 100644
--- a/docs/sdk/typescript/escrow/classes/EscrowClient.md
+++ b/docs/sdk/typescript/escrow/classes/EscrowClient.md
@@ -102,22 +102,12 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`constructor`](../../base/classes/BaseEthersClient.md#constructors)
-#### Source
+#### Defined in
-[escrow.ts:127](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L127)
+[escrow.ts:129](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L129)
## Properties
-### escrowFactoryContract
-
-> `private` **escrowFactoryContract**: `EscrowFactory`
-
-#### Source
-
-[escrow.ts:119](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L119)
-
-***
-
### networkData
> **networkData**: `NetworkData`
@@ -126,9 +116,9 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`networkData`](../../base/classes/BaseEthersClient.md#networkdata)
-#### Source
+#### Defined in
-[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
+[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
***
@@ -140,9 +130,9 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`runner`](../../base/classes/BaseEthersClient.md#runner)
-#### Source
+#### Defined in
-[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
+[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
## Methods
@@ -158,7 +148,7 @@ This function cancels the specified escrow, sends the balance to the canceler an
Address of the escrow.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -186,9 +176,9 @@ const escrowClient = await EscrowClient.build(signer);
await escrowClient.abort('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:835](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L835)
+[escrow.ts:837](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L837)
***
@@ -208,7 +198,7 @@ Address of the escrow.
Array of addresses of trusted handlers to add.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -237,9 +227,9 @@ const trustedHandlers = ['0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', '0xf39Fd6
await escrowClient.addTrustedHandlers('0x62dD51230A30401C455c8398d06F85e4EaB6309f', trustedHandlers);
```
-#### Source
+#### Defined in
-[escrow.ts:883](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L883)
+[escrow.ts:885](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L885)
***
@@ -271,7 +261,7 @@ Final results file url.
Final results file hash.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -304,9 +294,9 @@ const resultsHash'b5dad76bf6772c0f07fd5e048f6e75a5f86ee079';
await escrowClient.bulkPayOut('0x62dD51230A30401C455c8398d06F85e4EaB6309f', recipients, amounts, resultsUrl, resultsHash);
```
-#### Source
+#### Defined in
-[escrow.ts:648](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L648)
+[escrow.ts:650](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L650)
***
@@ -322,7 +312,7 @@ This function cancels the specified escrow and sends the balance to the canceler
Address of the escrow to cancel.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -350,9 +340,9 @@ const escrowClient = await EscrowClient.build(signer);
await escrowClient.cancel('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:751](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L751)
+[escrow.ts:753](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L753)
***
@@ -368,7 +358,7 @@ This function sets the status of an escrow to completed.
Address of the escrow.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -396,9 +386,9 @@ const escrowClient = await EscrowClient.build(signer);
await escrowClient.complete('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:590](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L590)
+[escrow.ts:592](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L592)
***
@@ -463,9 +453,9 @@ const escrowConfig = {
const escrowAddress = await escrowClient.createAndSetupEscrow(tokenAddress, trustedHandlers, jobRequesterId, escrowConfig);
```
-#### Source
+#### Defined in
-[escrow.ts:413](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L413)
+[escrow.ts:415](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L415)
***
@@ -489,7 +479,7 @@ Array of addresses that can perform actions on the contract.
Job Requester Id
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -520,9 +510,9 @@ const jobRequesterId = "job-requester-id";
const escrowAddress = await escrowClient.createEscrow(tokenAddress, trustedHandlers, jobRequesterId);
```
-#### Source
+#### Defined in
-[escrow.ts:207](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L207)
+[escrow.ts:209](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L209)
***
@@ -542,7 +532,7 @@ Address of the escrow to fund.
Amount to be added as funds.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -569,9 +559,9 @@ const amount = ethers.parseUnits(5, 'ether'); //convert from ETH to WEI
await escrowClient.fund('0x62dD51230A30401C455c8398d06F85e4EaB6309f', amount);
```
-#### Source
+#### Defined in
-[escrow.ts:461](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L461)
+[escrow.ts:463](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L463)
***
@@ -607,31 +597,9 @@ const escrowClient = await EscrowClient.build(signer);
const balance = await escrowClient.getBalance('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
-
-[escrow.ts:938](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L938)
-
-***
-
-### getEscrowContract()
-
-> `private` **getEscrowContract**(`escrowAddress`): `Escrow`
-
-Connects to the escrow contract
-
-#### Parameters
-
-• **escrowAddress**: `string`
-
-Escrow address to connect to
-
-#### Returns
-
-`Escrow`
-
-#### Source
+#### Defined in
-[escrow.ts:167](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L167)
+[escrow.ts:940](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L940)
***
@@ -667,9 +635,9 @@ const escrowClient = await EscrowClient.build(signer);
const oracleAddress = await escrowClient.getExchangeOracleAddress('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1318](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1318)
+[escrow.ts:1320](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1320)
***
@@ -705,9 +673,9 @@ const escrowClient = await EscrowClient.build(signer);
const factoryAddress = await escrowClient.getFactoryAddress('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1356](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1356)
+[escrow.ts:1358](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1358)
***
@@ -743,9 +711,9 @@ const escrowClient = await EscrowClient.build(signer);
const intemediateResultsUrl = await escrowClient.getIntermediateResultsUrl('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1090](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1090)
+[escrow.ts:1092](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1092)
***
@@ -781,9 +749,9 @@ const escrowClient = await EscrowClient.build(signer);
const jobLauncherAddress = await escrowClient.getJobLauncherAddress('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1242](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1242)
+[escrow.ts:1244](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1244)
***
@@ -819,9 +787,9 @@ const escrowClient = await EscrowClient.build(signer);
const manifestHash = await escrowClient.getManifestHash('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:976](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L976)
+[escrow.ts:978](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L978)
***
@@ -857,9 +825,9 @@ const escrowClient = await EscrowClient.build(signer);
const manifestUrl = await escrowClient.getManifestUrl('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1014](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1014)
+[escrow.ts:1016](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1016)
***
@@ -895,9 +863,9 @@ const escrowClient = await EscrowClient.build(signer);
const oracleAddress = await escrowClient.getRecordingOracleAddress('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1204](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1204)
+[escrow.ts:1206](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1206)
***
@@ -933,9 +901,9 @@ const escrowClient = await EscrowClient.build(signer);
const oracleAddress = await escrowClient.getReputationOracleAddress('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1280](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1280)
+[escrow.ts:1282](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1282)
***
@@ -971,9 +939,9 @@ const escrowClient = await EscrowClient.build(signer);
const resultsUrl = await escrowClient.getResultsUrl('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1052](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1052)
+[escrow.ts:1054](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1054)
***
@@ -1009,9 +977,9 @@ const escrowClient = await EscrowClient.build(signer);
const status = await escrowClient.getStatus('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1166](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1166)
+[escrow.ts:1168](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1168)
***
@@ -1047,9 +1015,9 @@ const escrowClient = await EscrowClient.build(signer);
const tokenAddress = await escrowClient.getTokenAddress('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[escrow.ts:1128](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1128)
+[escrow.ts:1130](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1130)
***
@@ -1069,7 +1037,7 @@ Address of the escrow to set up.
Escrow configuration parameters.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -1108,9 +1076,9 @@ const escrowConfig = {
await escrowClient.setup(escrowAddress, escrowConfig);
```
-#### Source
+#### Defined in
-[escrow.ts:288](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L288)
+[escrow.ts:290](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L290)
***
@@ -1134,7 +1102,7 @@ Results file url.
Results file hash.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -1162,9 +1130,9 @@ const escrowClient = await EscrowClient.build(signer);
await storeResults.storeResults('0x62dD51230A30401C455c8398d06F85e4EaB6309f', 'http://localhost/results.json', 'b5dad76bf6772c0f07fd5e048f6e75a5f86ee079');
```
-#### Source
+#### Defined in
-[escrow.ts:526](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L526)
+[escrow.ts:528](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L528)
***
@@ -1194,6 +1162,6 @@ Thrown if the provider does not exist for the provided Signer
Thrown if the network's chainId is not supported
-#### Source
+#### Defined in
-[escrow.ts:145](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L145)
+[escrow.ts:147](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L147)
diff --git a/docs/sdk/typescript/escrow/classes/EscrowUtils.md b/docs/sdk/typescript/escrow/classes/EscrowUtils.md
index aac8ae022f..e149999dc7 100644
--- a/docs/sdk/typescript/escrow/classes/EscrowUtils.md
+++ b/docs/sdk/typescript/escrow/classes/EscrowUtils.md
@@ -32,7 +32,7 @@ yarn install @human-protocol/sdk
import { ChainId, EscrowUtils } from '@human-protocol/sdk';
const escrowAddresses = new EscrowUtils.getEscrows({
- networks: [ChainId.POLYGON_AMOY]
+ network: ChainId.POLYGON_AMOY
});
```
@@ -130,9 +130,9 @@ import { ChainId, EscrowUtils } from '@human-protocol/sdk';
const escrowData = new EscrowUtils.getEscrow(ChainId.POLYGON_AMOY, "0x1234567890123456789012345678901234567890");
```
-#### Source
+#### Defined in
-[escrow.ts:1633](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1633)
+[escrow.ts:1646](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1646)
***
@@ -146,7 +146,7 @@ This function returns an array of escrows based on the specified filter paramete
```ts
interface IEscrowsFilter {
- networks: ChainId[];
+ chainId: ChainId;
launcher?: string;
reputationOracle?: string;
recordingOracle?: string;
@@ -155,6 +155,9 @@ interface IEscrowsFilter {
status?: EscrowStatus;
from?: Date;
to?: Date;
+ first?: number;
+ skip?: number;
+ orderDirection?: OrderDirection;
}
```
@@ -180,6 +183,13 @@ enum ChainId {
}
```
+```ts
+enum OrderDirection {
+ ASC = 'asc',
+ DESC = 'desc',
+}
+```
+
```ts
enum EscrowStatus {
Launched,
@@ -239,11 +249,124 @@ const filters: IEscrowsFilter = {
status: EscrowStatus.Pending,
from: new Date(2023, 4, 8),
to: new Date(2023, 5, 8),
- networks: [ChainId.POLYGON_AMOY]
+ chainId: ChainId.POLYGON_AMOY
};
const escrowDatas = await EscrowUtils.getEscrows(filters);
```
-#### Source
+#### Defined in
+
+[escrow.ts:1517](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1517)
+
+***
+
+### getStatusEvents()
+
+> `static` **getStatusEvents**(`chainId`, `statuses`?, `from`?, `to`?, `launcher`?, `first`?, `skip`?, `orderDirection`?): `Promise`\<`StatusEvent`[]\>
+
+This function returns the status events for a given set of networks within an optional date range.
+
+> This uses Subgraph
+
+**Input parameters**
+
+```ts
+enum ChainId {
+ ALL = -1,
+ MAINNET = 1,
+ RINKEBY = 4,
+ GOERLI = 5,
+ SEPOLIA = 11155111,
+ BSC_MAINNET = 56,
+ BSC_TESTNET = 97,
+ POLYGON = 137,
+ POLYGON_MUMBAI = 80001,
+ POLYGON_AMOY = 80002,
+ MOONBEAM = 1284,
+ MOONBASE_ALPHA = 1287,
+ AVALANCHE = 43114,
+ AVALANCHE_TESTNET = 43113,
+ CELO = 42220,
+ CELO_ALFAJORES = 44787,
+ LOCALHOST = 1338,
+ XLAYER_TESTNET = 195,
+ XLAYER = 196,
+}
+```
+
+```ts
+enum OrderDirection {
+ ASC = 'asc',
+ DESC = 'desc',
+}
+```
+
+```ts
+type Status = {
+ escrowAddress: string;
+ timestamp: string;
+ status: string;
+};
+```
+
+#### Parameters
+
+• **chainId**: `ChainId`
+
+List of network IDs to query for status events.
+
+• **statuses?**: `EscrowStatus`[]
+
+Optional array of statuses to query for. If not provided, queries for all statuses.
+
+• **from?**: `Date`
+
+Optional start date to filter events.
+
+• **to?**: `Date`
+
+Optional end date to filter events.
+
+• **launcher?**: `string`
+
+Optional launcher address to filter events. Must be a valid Ethereum address.
+
+• **first?**: `number`
+
+Optional number of transactions per page. Default is 10.
+
+• **skip?**: `number`
+
+Optional number of transactions to skip. Default is 0.
+
+• **orderDirection?**: `OrderDirection`
+
+Optional order of the results. Default is DESC.
+
+#### Returns
+
+`Promise`\<`StatusEvent`[]\>
+
+- Array of status events with their corresponding statuses.
+
+**Code example**
+
+```ts
+import { ChainId, EscrowUtils, EscrowStatus } from '@human-protocol/sdk';
+
+(async () => {
+ const fromDate = new Date('2023-01-01');
+ const toDate = new Date('2023-12-31');
+ const statusEvents = await EscrowUtils.getStatusEvents(
+ [ChainId.POLYGON, ChainId.MAINNET],
+ [EscrowStatus.Pending, EscrowStatus.Complete],
+ fromDate,
+ toDate
+ );
+ console.log(statusEvents);
+})();
+```
+
+#### Defined in
-[escrow.ts:1505](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1505)
+[escrow.ts:1744](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/escrow.ts#L1744)
diff --git a/docs/sdk/typescript/kvstore/classes/KVStoreClient.md b/docs/sdk/typescript/kvstore/classes/KVStoreClient.md
index 3f8218a1ab..d01ec370f4 100644
--- a/docs/sdk/typescript/kvstore/classes/KVStoreClient.md
+++ b/docs/sdk/typescript/kvstore/classes/KVStoreClient.md
@@ -102,22 +102,12 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`constructor`](../../base/classes/BaseEthersClient.md#constructors)
-#### Source
+#### Defined in
-[kvstore.ts:104](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L104)
+[kvstore.ts:104](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L104)
## Properties
-### contract
-
-> `private` **contract**: `KVStore`
-
-#### Source
-
-[kvstore.ts:96](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L96)
-
-***
-
### networkData
> **networkData**: `NetworkData`
@@ -126,9 +116,9 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`networkData`](../../base/classes/BaseEthersClient.md#networkdata)
-#### Source
+#### Defined in
-[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
+[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
***
@@ -140,9 +130,9 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`runner`](../../base/classes/BaseEthersClient.md#runner)
-#### Source
+#### Defined in
-[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
+[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
## Methods
@@ -184,9 +174,9 @@ const kvstoreClient = await KVStoreClient.build(provider);
const value = await kvstoreClient.get('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', 'Role');
```
-#### Source
+#### Defined in
-[kvstore.ts:305](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L305)
+[kvstore.ts:305](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L305)
***
@@ -202,7 +192,7 @@ Gets the URL value of the given entity, and verify its hash.
Address from which to get the URL value.
-• **urlKey**: `string`= `'url'`
+• **urlKey**: `string` = `'url'`
Configurable URL key. `url` by default.
@@ -230,9 +220,9 @@ const linkedinUrl = await kvstoreClient.getFileUrlAndVerifyHash(
);
```
-#### Source
+#### Defined in
-[kvstore.ts:344](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L344)
+[kvstore.ts:344](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L344)
***
@@ -268,9 +258,9 @@ const kvstoreClient = await KVStoreClient.build(provider);
const publicKey = await kvstoreClient.getPublicKey('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266');
```
-#### Source
+#### Defined in
-[kvstore.ts:402](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L402)
+[kvstore.ts:402](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L402)
***
@@ -290,7 +280,7 @@ Key of the key-value pair
Value of the key-value pair
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -318,9 +308,9 @@ const kvstoreClient = await KVStoreClient.build(signer);
await kvstoreClient.set('Role', 'RecordingOracle');
```
-#### Source
+#### Defined in
-[kvstore.ts:167](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L167)
+[kvstore.ts:167](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L167)
***
@@ -340,7 +330,7 @@ Array of keys (keys and value must have the same order)
Array of values
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -370,9 +360,9 @@ const values = ['RecordingOracle', 'http://localhost'];
await kvstoreClient.set(keys, values);
```
-#### Source
+#### Defined in
-[kvstore.ts:210](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L210)
+[kvstore.ts:210](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L210)
***
@@ -388,11 +378,11 @@ Sets a URL value for the address that submits the transaction, and its hash.
URL to set
-• **urlKey**: `string`= `'url'`
+• **urlKey**: `string` = `'url'`
Configurable URL key. `url` by default.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -419,9 +409,9 @@ await kvstoreClient.setFileUrlAndHash('example.com');
await kvstoreClient.setFileUrlAndHash('linkedin.com/example', 'linkedin_url);
```
-#### Source
+#### Defined in
-[kvstore.ts:253](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L253)
+[kvstore.ts:253](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L253)
***
@@ -451,6 +441,6 @@ The Runner object to interact with the Ethereum network
- Thrown if the network's chainId is not supported
-#### Source
+#### Defined in
-[kvstore.ts:122](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L122)
+[kvstore.ts:122](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L122)
diff --git a/docs/sdk/typescript/kvstore/classes/KVStoreUtils.md b/docs/sdk/typescript/kvstore/classes/KVStoreUtils.md
index 73fb7cb0ec..eb2001fb35 100644
--- a/docs/sdk/typescript/kvstore/classes/KVStoreUtils.md
+++ b/docs/sdk/typescript/kvstore/classes/KVStoreUtils.md
@@ -32,7 +32,7 @@ yarn install @human-protocol/sdk
import { ChainId, KVStoreUtils } from '@human-protocol/sdk';
const KVStoreAddresses = new KVStoreUtils.getData({
- networks: [ChainId.POLYGON_AMOY]
+ network: ChainId.POLYGON_AMOY
});
```
@@ -111,6 +111,6 @@ const kvStoreData = await KVStoreUtils.getKVStoreData(ChainId.POLYGON_AMOY, "0x1
console.log(kvStoreData);
```
-#### Source
+#### Defined in
-[kvstore.ts:498](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L498)
+[kvstore.ts:498](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/kvstore.ts#L498)
diff --git a/docs/sdk/typescript/operator/classes/OperatorUtils.md b/docs/sdk/typescript/operator/classes/OperatorUtils.md
index c685983503..52927dc211 100644
--- a/docs/sdk/typescript/operator/classes/OperatorUtils.md
+++ b/docs/sdk/typescript/operator/classes/OperatorUtils.md
@@ -46,9 +46,9 @@ import { OperatorUtils, ChainId } from '@human-protocol/sdk';
const leader = await OperatorUtils.getLeader(ChainId.POLYGON_AMOY, '0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[operator.ts:44](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L44)
+[operator.ts:44](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L44)
***
@@ -81,9 +81,9 @@ const filter: ILeadersFilter = {
const leaders = await OperatorUtils.getLeaders(filter);
```
-#### Source
+#### Defined in
-[operator.ts:99](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L99)
+[operator.ts:99](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L99)
***
@@ -119,9 +119,9 @@ import { OperatorUtils, ChainId } from '@human-protocol/sdk';
const operators = await OperatorUtils.getReputationNetworkOperators(ChainId.POLYGON_AMOY, '0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[operator.ts:155](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L155)
+[operator.ts:151](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L151)
***
@@ -153,6 +153,6 @@ import { OperatorUtils, ChainId } from '@human-protocol/sdk';
const rewards = await OperatorUtils.getRewards(ChainId.POLYGON_AMOY, '0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[operator.ts:207](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L207)
+[operator.ts:199](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/operator.ts#L199)
diff --git a/docs/sdk/typescript/staking/classes/StakingClient.md b/docs/sdk/typescript/staking/classes/StakingClient.md
index a14e189cb0..3180e7b1d1 100644
--- a/docs/sdk/typescript/staking/classes/StakingClient.md
+++ b/docs/sdk/typescript/staking/classes/StakingClient.md
@@ -102,9 +102,9 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`constructor`](../../base/classes/BaseEthersClient.md#constructors)
-#### Source
+#### Defined in
-[staking.ts:111](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L111)
+[staking.ts:111](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L111)
## Properties
@@ -112,9 +112,9 @@ The Runner object to interact with the Ethereum network
> **escrowFactoryContract**: `EscrowFactory`
-#### Source
+#### Defined in
-[staking.ts:102](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L102)
+[staking.ts:102](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L102)
***
@@ -126,9 +126,9 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`networkData`](../../base/classes/BaseEthersClient.md#networkdata)
-#### Source
+#### Defined in
-[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
+[base.ts:12](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L12)
***
@@ -136,9 +136,9 @@ The Runner object to interact with the Ethereum network
> **rewardPoolContract**: `RewardPool`
-#### Source
+#### Defined in
-[staking.ts:103](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L103)
+[staking.ts:103](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L103)
***
@@ -150,9 +150,9 @@ The Runner object to interact with the Ethereum network
[`BaseEthersClient`](../../base/classes/BaseEthersClient.md).[`runner`](../../base/classes/BaseEthersClient.md#runner)
-#### Source
+#### Defined in
-[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
+[base.ts:11](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/base.ts#L11)
***
@@ -160,9 +160,9 @@ The Runner object to interact with the Ethereum network
> **stakingContract**: `Staking`
-#### Source
+#### Defined in
-[staking.ts:101](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L101)
+[staking.ts:101](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L101)
***
@@ -170,9 +170,9 @@ The Runner object to interact with the Ethereum network
> **tokenContract**: `HMToken`
-#### Source
+#### Defined in
-[staking.ts:100](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L100)
+[staking.ts:100](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L100)
## Methods
@@ -194,7 +194,7 @@ Address of the escrow contract to allocate in.
Amount in WEI of tokens to allocate.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -221,9 +221,9 @@ const amount = ethers.parseUnits(5, 'ether'); //convert from ETH to WEI
await stakingClient.allocate('0x62dD51230A30401C455c8398d06F85e4EaB6309f', amount);
```
-#### Source
+#### Defined in
-[staking.ts:458](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L458)
+[staking.ts:458](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L458)
***
@@ -239,7 +239,7 @@ This function approves the staking contract to transfer a specified amount of to
Amount in WEI of tokens to approve for stake.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -266,31 +266,9 @@ const amount = ethers.parseUnits(5, 'ether'); //convert from ETH to WEI
await stakingClient.approveStake(amount);
```
-#### Source
+#### Defined in
-[staking.ts:203](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L203)
-
-***
-
-### checkValidEscrow()
-
-> `private` **checkValidEscrow**(`escrowAddress`): `Promise`\<`void`\>
-
-Check if escrow exists
-
-#### Parameters
-
-• **escrowAddress**: `string`
-
-Escrow address to check against
-
-#### Returns
-
-`Promise`\<`void`\>
-
-#### Source
-
-[staking.ts:167](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L167)
+[staking.ts:203](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L203)
***
@@ -309,7 +287,7 @@ This function drops the allocation from a specific escrow.
Address of the escrow contract to close allocation from.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -335,9 +313,9 @@ const stakingClient = await StakingClient.build(signer);
await stakingClient.closeAllocation('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[staking.ts:511](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L511)
+[staking.ts:511](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L511)
***
@@ -355,7 +333,7 @@ This function drops the allocation from a specific escrow.
Escrow address from which rewards are distributed.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -381,9 +359,9 @@ const stakingClient = await StakingClient.build(signer);
await stakingClient.distributeReward('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[staking.ts:554](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L554)
+[staking.ts:554](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L554)
***
@@ -419,9 +397,9 @@ const stakingClient = await StakingClient.build(provider);
const allocationInfo = await stakingClient.getAllocation('0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[staking.ts:591](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L591)
+[staking.ts:591](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L591)
***
@@ -449,7 +427,7 @@ Address of the escrow which allocation will be slashed
Amount in WEI of tokens to unstake.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -476,9 +454,9 @@ const amount = ethers.parseUnits(5, 'ether'); //convert from ETH to WEI
await stakingClient.slash('0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', '0x62dD51230A30401C455c8398d06F85e4EaB6309f', amount);
```
-#### Source
+#### Defined in
-[staking.ts:387](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L387)
+[staking.ts:387](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L387)
***
@@ -496,7 +474,7 @@ This function stakes a specified amount of tokens on a specific network.
Amount in WEI of tokens to stake.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -524,9 +502,9 @@ await stakingClient.approveStake(amount); // if it was already approved before,
await stakingClient.approveStake(amount);
```
-#### Source
+#### Defined in
-[staking.ts:258](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L258)
+[staking.ts:258](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L258)
***
@@ -544,7 +522,7 @@ This function unstakes tokens from staking contract. The unstaked tokens stay lo
Amount in WEI of tokens to unstake.
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -571,9 +549,9 @@ const amount = ethers.parseUnits(5, 'ether'); //convert from ETH to WEI
await stakingClient.unstake(amount);
```
-#### Source
+#### Defined in
-[staking.ts:303](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L303)
+[staking.ts:303](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L303)
***
@@ -587,7 +565,7 @@ This function withdraws unstaked and non locked tokens form staking contract to
#### Parameters
-• **txOptions?**: `Overrides`= `{}`
+• **txOptions?**: `Overrides` = `{}`
Additional transaction parameters (optional, defaults to an empty object).
@@ -613,9 +591,9 @@ const stakingClient = await StakingClient.build(signer);
await stakingClient.withdraw();
```
-#### Source
+#### Defined in
-[staking.ts:349](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L349)
+[staking.ts:349](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L349)
***
@@ -645,6 +623,6 @@ The Runner object to interact with the Ethereum network
- Thrown if the network's chainId is not supported
-#### Source
+#### Defined in
-[staking.ts:145](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L145)
+[staking.ts:145](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/staking.ts#L145)
diff --git a/docs/sdk/typescript/statistics/classes/StatisticsClient.md b/docs/sdk/typescript/statistics/classes/StatisticsClient.md
index 0f13ec3709..3638e58006 100644
--- a/docs/sdk/typescript/statistics/classes/StatisticsClient.md
+++ b/docs/sdk/typescript/statistics/classes/StatisticsClient.md
@@ -60,9 +60,9 @@ The network information required to connect to the Statistics contract
[`StatisticsClient`](StatisticsClient.md)
-#### Source
+#### Defined in
-[statistics.ts:69](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L69)
+[statistics.ts:70](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L70)
## Properties
@@ -70,9 +70,9 @@ The network information required to connect to the Statistics contract
> **networkData**: `NetworkData`
-#### Source
+#### Defined in
-[statistics.ts:61](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L61)
+[statistics.ts:62](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L62)
***
@@ -80,9 +80,9 @@ The network information required to connect to the Statistics contract
> **subgraphUrl**: `string`
-#### Source
+#### Defined in
-[statistics.ts:62](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L62)
+[statistics.ts:63](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L63)
## Methods
@@ -120,7 +120,7 @@ type EscrowStatistics = {
#### Parameters
-• **params**: `IStatisticsParams`= `{}`
+• **params**: `IStatisticsParams` = `{}`
Statistics params with duration data
@@ -144,9 +144,52 @@ const escrowStatisticsApril = await statisticsClient.getEscrowStatistics({
});
```
-#### Source
+#### Defined in
-[statistics.ts:123](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L123)
+[statistics.ts:124](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L124)
+
+***
+
+### getHMTHolders()
+
+> **getHMTHolders**(`params`): `Promise`\<`HMTHolder`[]\>
+
+This function returns the holders of the HMToken with optional filters and ordering.
+
+**Input parameters**
+
+#### Parameters
+
+• **params**: `IHMTHoldersParams` = `{}`
+
+HMT Holders params with filters and ordering
+
+#### Returns
+
+`Promise`\<`HMTHolder`[]\>
+
+List of HMToken holders.
+
+**Code example**
+
+```ts
+import { StatisticsClient, ChainId, NETWORKS } from '@human-protocol/sdk';
+
+const statisticsClient = new StatisticsClient(NETWORKS[ChainId.POLYGON_AMOY]);
+
+const hmtHolders = await statisticsClient.getHMTHolders({
+ orderDirection: 'asc',
+});
+
+console.log('HMT holders:', hmtHolders.map((h) => ({
+ ...h,
+ balance: h.balance.toString(),
+})));
+```
+
+#### Defined in
+
+[statistics.ts:466](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L466)
***
@@ -189,7 +232,7 @@ type HMTStatistics = {
#### Parameters
-• **params**: `IStatisticsParams`= `{}`
+• **params**: `IStatisticsParams` = `{}`
Statistics params with duration data
@@ -240,9 +283,9 @@ console.log('HMT statistics from 5/8 - 6/8:', {
});
```
-#### Source
+#### Defined in
-[statistics.ts:396](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L396)
+[statistics.ts:397](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L397)
***
@@ -277,7 +320,7 @@ type PaymentStatistics = {
#### Parameters
-• **params**: `IStatisticsParams`= `{}`
+• **params**: `IStatisticsParams` = `{}`
Statistics params with duration data
@@ -322,9 +365,9 @@ console.log(
);
```
-#### Source
+#### Defined in
-[statistics.ts:287](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L287)
+[statistics.ts:288](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L288)
***
@@ -357,7 +400,7 @@ type WorkerStatistics = {
#### Parameters
-• **params**: `IStatisticsParams`= `{}`
+• **params**: `IStatisticsParams` = `{}`
Statistics params with duration data
@@ -381,6 +424,6 @@ const workerStatisticsApril = await statisticsClient.getWorkerStatistics({
});
```
-#### Source
+#### Defined in
-[statistics.ts:198](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L198)
+[statistics.ts:199](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/statistics.ts#L199)
diff --git a/docs/sdk/typescript/storage/classes/StorageClient.md b/docs/sdk/typescript/storage/classes/StorageClient.md
index 58d80d8336..d08fddf1ed 100644
--- a/docs/sdk/typescript/storage/classes/StorageClient.md
+++ b/docs/sdk/typescript/storage/classes/StorageClient.md
@@ -75,29 +75,9 @@ Optional. Cloud storage access data. If credentials is not provided - use an ano
[`StorageClient`](StorageClient.md)
-#### Source
+#### Defined in
-[storage.ts:73](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L73)
-
-## Properties
-
-### ~~client~~
-
-> `private` **client**: `Client`
-
-#### Source
-
-[storage.ts:64](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L64)
-
-***
-
-### ~~clientParams~~
-
-> `private` **clientParams**: `StorageParams`
-
-#### Source
-
-[storage.ts:65](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L65)
+[storage.ts:73](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L73)
## Methods
@@ -139,9 +119,9 @@ const storageClient = new StorageClient(params, credentials);
const exists = await storageClient.bucketExists('bucket-name');
```
-#### Source
+#### Defined in
-[storage.ts:266](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L266)
+[storage.ts:266](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L266)
***
@@ -185,9 +165,9 @@ const keys = ['file1.json', 'file2.json'];
const files = await storageClient.downloadFiles(keys, 'bucket-name');
```
-#### Source
+#### Defined in
-[storage.ts:113](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L113)
+[storage.ts:113](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L113)
***
@@ -229,9 +209,9 @@ const storageClient = new StorageClient(params, credentials);
const fileNames = await storageClient.listObjects('bucket-name');
```
-#### Source
+#### Defined in
-[storage.ts:297](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L297)
+[storage.ts:297](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L297)
***
@@ -280,9 +260,9 @@ const files = [file1, file2];
const uploadedFiles = await storageClient.uploadFiles(files, 'bucket-name');
```
-#### Source
+#### Defined in
-[storage.ts:201](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L201)
+[storage.ts:201](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L201)
***
@@ -312,6 +292,6 @@ import { StorageClient } from '@human-protocol/sdk';
const file = await storageClient.downloadFileFromUrl('http://localhost/file.json');
```
-#### Source
+#### Defined in
-[storage.ts:148](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L148)
+[storage.ts:148](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/storage.ts#L148)
diff --git a/docs/sdk/typescript/transaction/classes/TransactionUtils.md b/docs/sdk/typescript/transaction/classes/TransactionUtils.md
index 394a70a38f..c78b72f6bf 100644
--- a/docs/sdk/typescript/transaction/classes/TransactionUtils.md
+++ b/docs/sdk/typescript/transaction/classes/TransactionUtils.md
@@ -48,9 +48,9 @@ import { TransactionUtils, ChainId } from '@human-protocol/sdk';
const transaction = await TransactionUtils.getTransaction(ChainId.POLYGON, '0x62dD51230A30401C455c8398d06F85e4EaB6309f');
```
-#### Source
+#### Defined in
-[transaction.ts:34](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts#L34)
+[transaction.ts:34](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts#L34)
***
@@ -66,13 +66,16 @@ This function returns all transaction details based on the provided filter.
```ts
interface ITransactionsFilter {
- networks: ChainId[]; // List of chain IDs to query.
+ chainId: ChainId; // List of chain IDs to query.
fromAddress?: string; // (Optional) The address from which transactions are sent.
toAddress?: string; // (Optional) The address to which transactions are sent.
startDate?: Date; // (Optional) The start date to filter transactions (inclusive).
endDate?: Date; // (Optional) The end date to filter transactions (inclusive).
startBlock?: number; // (Optional) The start block number to filter transactions (inclusive).
endBlock?: number; // (Optional) The end block number to filter transactions (inclusive).
+ first?: number; // (Optional) Number of transactions per page. Default is 10.
+ skip?: number; // (Optional) Number of transactions to skip. Default is 0.
+ orderDirection?: OrderDirection; // (Optional) Order of the results. Default is DESC.
}
```
@@ -103,16 +106,19 @@ Returns an array with all the transaction details.
**Code example**
```ts
-import { TransactionUtils, ChainId } from '@human-protocol/sdk';
+import { TransactionUtils, ChainId, OrderDirection } from '@human-protocol/sdk';
const filter: ITransactionsFilter = {
- networks: [ChainId.POLYGON],
+ chainId: ChainId.POLYGON,
startDate: new Date('2022-01-01'),
- endDate: new Date('2022-12-31')
+ endDate: new Date('2022-12-31'),
+ first: 10,
+ skip: 0,
+ orderDirection: OrderDirection.DESC,
};
const transactions = await TransactionUtils.getTransactions(filter);
```
-#### Source
+#### Defined in
-[transaction.ts:103](https://github.com/humanprotocol/human-protocol/blob/13ee19fe4d0f80f76bcbeb92a0bed3f617c0df35/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts#L103)
+[transaction.ts:109](https://github.com/humanprotocol/human-protocol/blob/be3631cc39e3198133a9145c1c7bd03c2836462a/packages/sdk/typescript/human-protocol-sdk/src/transaction.ts#L109)
diff --git a/package.json b/package.json
index 7901f1dc70..9d98c0d6e8 100644
--- a/package.json
+++ b/package.json
@@ -6,40 +6,19 @@
"repository": "https://github.com/humanprotocol/human-protocol",
"license": "MIT",
"scripts": {
- "core:test": "yarn workspace @human-protocol/core test",
- "core:lint": "yarn workspace @human-protocol/core lint",
- "subgraph:test": "yarn workspace @human-protocol/subgraph test",
- "subgraph:lint": "yarn workspace @human-protocol/subgraph lint",
- "dashboard-ui:start": "yarn workspace @human-protocol/dashboard-ui start",
- "dashboard-ui:test": "yarn workspace @human-protocol/dashboard-ui test",
- "dashboard-ui:lint": "yarn workspace @human-protocol/dashboard-ui lint",
- "faucet-server:start": "yarn workspace @human-protocol/faucet-server start",
- "faucet-server:test": "yarn workspace @human-protocol/faucet-server test",
- "faucet-server:lint": "yarn workspace @human-protocol/faucet-server lint",
- "fortune-v3:test": "yarn workspace @human-protocol/fortune-v3 test",
- "fortune-v3:lint": "yarn workspace @human-protocol/fortune-v3 lint",
- "job-launcher-server:test": "yarn workspace @human-protocol/job-launcher-server test",
- "job-launcher-server:lint": "yarn workspace @human-protocol/job-launcher-server lint",
- "job-launcher-client:test": "yarn workspace @human-protocol/job-launcher-client test",
- "job-launcher-client:lint": "yarn workspace @human-protocol/job-launcher-client lint",
- "human-app-server:test": "yarn workspace @human-protocol/human-app-server test",
- "human-app-server:lint": "yarn workspace @human-protocol/human-app-server lint",
- "reputation-oracle:test": "yarn workspace @human-protocol/reputation-oracle test",
- "reputation-oracle:lint": "yarn workspace @human-protocol/reputation-oracle lint",
- "sdk:test": "yarn workspace @human-protocol/sdk test",
- "sdk:lint": "yarn workspace @human-protocol/sdk lint",
- "test": "concurrently npm:core:test npm:subgraph:test npm:dashboard-ui:test npm:fortune-v3:test npm:sdk:test npm:faucet-server:test npm:job-launcher-server:test npm:job-launcher-client:test npm:reputation-oracle:test",
- "lint": "concurrently npm:core:lint npm:subgraph:lint npm:dashboard-ui:lint npm:fortune-v3:lint npm:sdk:lint npm:faucet-server:lint npm:job-launcher-server:lint npm:job-launcher-client:lint npm:reputation-oracle:lint",
+ "test": "concurrently \"yarn workspace @human-protocol/core test\" \"yarn workspace @human-protocol/sdk test\" \"yarn workspace @human-protocol/subgraph test\" \"yarn workspace @human-protocol/dashboard-ui test\" \"yarn workspace @human-protocol/faucet-server test\" \"yarn workspace @human-protocol/job-launcher-server test\" \"yarn workspace @human-protocol/job-launcher-client test\" \"yarn workspace @human-protocol/human-app-server test\" \"yarn workspace @human-protocol/reputation-oracle test\" \"yarn workspace @human-protocol/fortune-exchange-oracle-server test\" \"yarn workspace @human-protocol/fortune-recording-oracle test\"",
+ "lint": "concurrently \"yarn workspace @human-protocol/core lint\" \"yarn workspace @human-protocol/sdk lint\" \"yarn workspace @human-protocol/subgraph lint\" \"yarn workspace @human-protocol/dashboard-ui lint\" \"yarn workspace @human-protocol/faucet-server lint\" \"yarn workspace @human-protocol/job-launcher-server lint\" \"yarn workspace @human-protocol/job-launcher-client lint\" \"yarn workspace @human-protocol/human-app-server lint\" \"yarn workspace @human-protocol/reputation-oracle lint\" \"yarn workspace @human-protocol/fortune-exchange-oracle-server lint\" \"yarn workspace @human-protocol/fortune-recording-oracle lint\"",
"prepare": "husky install",
"postinstall": "yarn workspace @human-protocol/sdk build"
},
"workspaces": {
"packages": [
- "packages/**/*"
+ "packages/**/*",
+ "!packages/apps/dashboard/admin"
]
},
"devDependencies": {
- "@apollo/client": "^3.7.12",
+ "@apollo/client": "^3.11.1",
"@babel/core": "^7.23.5",
"@babel/preset-env": "^7.24.3",
"@babel/preset-react": "^7.18.6",
@@ -54,26 +33,28 @@
"dotenv": "^16.3.2",
"eslint": "^8.55.0",
"eslint-config-prettier": "^9.1.0",
- "eslint-plugin-jest": "^27.1.5",
+ "eslint-plugin-jest": "^28.6.0",
"eslint-plugin-prettier": "^5.1.3",
"ethers": "^6.12.1",
"husky": "^9.0.11",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
- "lint-staged": "^15.2.5",
+ "lint-staged": "^15.2.7",
"prettier": "^3.2.5",
- "ts-jest": "^29.1.1",
+ "ts-jest": "^29.2.2",
"ts-node": "^10.9.2",
"typescript": "^4.9.3"
},
"resolutions": {
- "ejs": "^3.1.8",
+ "ejs": "^3.1.10",
"gluegun": "^5.0.0",
"mocha": "^10.0.0",
"node-fetch": "^2.6.7",
"node-forge": "^1.0.0",
"qrcode": "^1.5.0",
"semver": "^7.5.2",
- "undici": "^6.11.1"
+ "undici": "^6.11.1",
+ "ws": "^8.17.1",
+ "fast-xml-parser": "4.4.1"
}
-}
\ No newline at end of file
+}
diff --git a/packages/apps/dashboard/admin/config/middlewares.ts b/packages/apps/dashboard/admin/config/middlewares.ts
index 3ab20d955b..9ccd22f5b5 100644
--- a/packages/apps/dashboard/admin/config/middlewares.ts
+++ b/packages/apps/dashboard/admin/config/middlewares.ts
@@ -1,11 +1,11 @@
export default [
+ 'strapi::logger',
+ 'strapi::cors',
+ 'strapi::body',
'strapi::errors',
'strapi::security',
- 'strapi::cors',
'strapi::poweredBy',
- 'strapi::logger',
'strapi::query',
- 'strapi::body',
'strapi::session',
'strapi::favicon',
'strapi::public',
diff --git a/packages/apps/dashboard/admin/package.json b/packages/apps/dashboard/admin/package.json
index 46f22990c1..312f3771bd 100644
--- a/packages/apps/dashboard/admin/package.json
+++ b/packages/apps/dashboard/admin/package.json
@@ -6,25 +6,33 @@
"scripts": {
"develop": "strapi develop",
"start": "strapi start",
- "prebuild": "yarn workspace @human-protocol/core install && yarn workspace @human-protocol/sdk install && yarn workspace @human-protocol/sdk build",
+ "prebuild": "yarn install",
"build": "strapi build",
"strapi": "strapi"
},
"devDependencies": {},
"dependencies": {
- "@human-protocol/sdk": "*",
- "@strapi/plugin-i18n": "4.16.2",
- "@strapi/plugin-users-permissions": "4.24.1",
- "@strapi/strapi": "4.24.2",
+ "@human-protocol/core": "^3.0.0",
+ "@human-protocol/sdk": "^3.0.0",
+ "@strapi/plugin-i18n": "4.25.1",
+ "@strapi/plugin-users-permissions": "4.25.1",
+ "@strapi/strapi": "4.25.1",
"axios": "^1.5.1",
"dayjs": "^1.11.10",
+ "ethers": "^6.13.1",
"graphql-request": "^6.1.0",
- "pg": "8.11.3",
+ "pg": "8.12.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-router-dom": "5.3.4",
"styled-components": "5.3.3",
- "viem": "^2.10.2"
+ "tar": "^7.4.0",
+ "viem": "^2.14.2"
+ },
+ "resolutions": {
+ "braces": "^3.0.3",
+ "tar": "^6.2.1",
+ "fast-xml-parser": "4.4.1"
},
"author": {
"name": "HUMAN Protocol"
diff --git a/packages/apps/dashboard/admin/yarn.lock b/packages/apps/dashboard/admin/yarn.lock
new file mode 100644
index 0000000000..be51158d4c
--- /dev/null
+++ b/packages/apps/dashboard/admin/yarn.lock
@@ -0,0 +1,11105 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@adraffy/ens-normalize@1.10.0":
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.0.tgz#d2a39395c587e092d77cbbc80acf956a54f38bf7"
+ integrity sha512-nA9XHtlAkYfJxY7bce8DcN7eKxWWCWkU+1GR9d+U6MbNpfwQp8TI7vqOsBsMcHoT4mBu2kypKoSKnghEzOOq5Q==
+
+"@adraffy/ens-normalize@1.10.1":
+ version "1.10.1"
+ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069"
+ integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==
+
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465"
+ integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==
+ dependencies:
+ "@babel/highlight" "^7.24.7"
+ picocolors "^1.0.0"
+
+"@babel/generator@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d"
+ integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==
+ dependencies:
+ "@babel/types" "^7.24.7"
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
+ jsesc "^2.5.1"
+
+"@babel/helper-annotate-as-pure@^7.22.5":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz#5373c7bc8366b12a033b4be1ac13a206c6656aab"
+ integrity sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==
+ dependencies:
+ "@babel/types" "^7.24.7"
+
+"@babel/helper-environment-visitor@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9"
+ integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==
+ dependencies:
+ "@babel/types" "^7.24.7"
+
+"@babel/helper-function-name@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2"
+ integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==
+ dependencies:
+ "@babel/template" "^7.24.7"
+ "@babel/types" "^7.24.7"
+
+"@babel/helper-hoist-variables@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee"
+ integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==
+ dependencies:
+ "@babel/types" "^7.24.7"
+
+"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.5":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b"
+ integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==
+ dependencies:
+ "@babel/traverse" "^7.24.7"
+ "@babel/types" "^7.24.7"
+
+"@babel/helper-plugin-utils@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz#98c84fe6fe3d0d3ae7bfc3a5e166a46844feb2a0"
+ integrity sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==
+
+"@babel/helper-split-export-declaration@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856"
+ integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==
+ dependencies:
+ "@babel/types" "^7.24.7"
+
+"@babel/helper-string-parser@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2"
+ integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==
+
+"@babel/helper-validator-identifier@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db"
+ integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==
+
+"@babel/highlight@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d"
+ integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.24.7"
+ chalk "^2.4.2"
+ js-tokens "^4.0.0"
+ picocolors "^1.0.0"
+
+"@babel/parser@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85"
+ integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==
+
+"@babel/plugin-syntax-jsx@^7.22.5":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz#39a1fa4a7e3d3d7f34e2acc6be585b718d30e02d"
+ integrity sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.24.7"
+
+"@babel/runtime-corejs3@^7.9.2":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.24.7.tgz#65a99097e4c28e6c3a174825591700cc5abd710e"
+ integrity sha512-eytSX6JLBY6PVAeQa2bFlDx/7Mmln/gaEpsit5a3WEvjGfiIytEsgAwuIXCPM0xvw0v0cJn3ilq0/TvXrW0kgA==
+ dependencies:
+ core-js-pure "^3.30.2"
+ regenerator-runtime "^0.14.0"
+
+"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.7.tgz#f4f0d5530e8dbdf59b3451b9b3e594b6ba082e12"
+ integrity sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
+"@babel/template@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315"
+ integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==
+ dependencies:
+ "@babel/code-frame" "^7.24.7"
+ "@babel/parser" "^7.24.7"
+ "@babel/types" "^7.24.7"
+
+"@babel/traverse@^7.24.7", "@babel/traverse@^7.4.5":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5"
+ integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==
+ dependencies:
+ "@babel/code-frame" "^7.24.7"
+ "@babel/generator" "^7.24.7"
+ "@babel/helper-environment-visitor" "^7.24.7"
+ "@babel/helper-function-name" "^7.24.7"
+ "@babel/helper-hoist-variables" "^7.24.7"
+ "@babel/helper-split-export-declaration" "^7.24.7"
+ "@babel/parser" "^7.24.7"
+ "@babel/types" "^7.24.7"
+ debug "^4.3.1"
+ globals "^11.1.0"
+
+"@babel/types@^7.24.7":
+ version "7.24.7"
+ resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2"
+ integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==
+ dependencies:
+ "@babel/helper-string-parser" "^7.24.7"
+ "@babel/helper-validator-identifier" "^7.24.7"
+ to-fast-properties "^2.0.0"
+
+"@casl/ability@6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@casl/ability/-/ability-6.5.0.tgz#a151a7637886099b8ffe52a96601225004a5c157"
+ integrity sha512-3guc94ugr5ylZQIpJTLz0CDfwNi0mxKVECj1vJUPAvs+Lwunh/dcuUjwzc4MHM9D8JOYX0XUZMEPedpB3vIbOw==
+ dependencies:
+ "@ucast/mongo2js" "^1.3.0"
+
+"@codemirror/autocomplete@^6.0.0":
+ version "6.16.3"
+ resolved "https://registry.yarnpkg.com/@codemirror/autocomplete/-/autocomplete-6.16.3.tgz#04d5a4e4e44ccae1ba525d47db53a5479bf46338"
+ integrity sha512-Vl/tIeRVVUCRDuOG48lttBasNQu8usGgXQawBXI7WJAiUDSFOfzflmEsZFZo48mAvAaa4FZ/4/yLLxFtdJaKYA==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.17.0"
+ "@lezer/common" "^1.0.0"
+
+"@codemirror/commands@^6.0.0", "@codemirror/commands@^6.1.0":
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/@codemirror/commands/-/commands-6.6.0.tgz#d308f143fe1b8896ca25fdb855f66acdaf019dd4"
+ integrity sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/state" "^6.4.0"
+ "@codemirror/view" "^6.27.0"
+ "@lezer/common" "^1.1.0"
+
+"@codemirror/lang-json@^6.0.1":
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/@codemirror/lang-json/-/lang-json-6.0.1.tgz#0a0be701a5619c4b0f8991f9b5e95fe33f462330"
+ integrity sha512-+T1flHdgpqDDlJZ2Lkil/rLiRy684WMLc74xUnjJH48GQdfJo/pudlTRreZmKwzP8/tGdKf83wlbAdOCzlJOGQ==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@lezer/json" "^1.0.0"
+
+"@codemirror/language@^6.0.0":
+ version "6.10.2"
+ resolved "https://registry.yarnpkg.com/@codemirror/language/-/language-6.10.2.tgz#4056dc219619627ffe995832eeb09cea6060be61"
+ integrity sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==
+ dependencies:
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.23.0"
+ "@lezer/common" "^1.1.0"
+ "@lezer/highlight" "^1.0.0"
+ "@lezer/lr" "^1.0.0"
+ style-mod "^4.0.0"
+
+"@codemirror/lint@^6.0.0":
+ version "6.8.1"
+ resolved "https://registry.yarnpkg.com/@codemirror/lint/-/lint-6.8.1.tgz#6427848815baaf68c08e98c7673b804d3d8c0e7f"
+ integrity sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==
+ dependencies:
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+ crelt "^1.0.5"
+
+"@codemirror/search@^6.0.0":
+ version "6.5.6"
+ resolved "https://registry.yarnpkg.com/@codemirror/search/-/search-6.5.6.tgz#8f858b9e678d675869112e475f082d1e8488db93"
+ integrity sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==
+ dependencies:
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+ crelt "^1.0.5"
+
+"@codemirror/state@^6.0.0", "@codemirror/state@^6.1.1", "@codemirror/state@^6.4.0":
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/@codemirror/state/-/state-6.4.1.tgz#da57143695c056d9a3c38705ed34136e2b68171b"
+ integrity sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==
+
+"@codemirror/theme-one-dark@^6.0.0":
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/@codemirror/theme-one-dark/-/theme-one-dark-6.1.2.tgz#fcef9f9cfc17a07836cb7da17c9f6d7231064df8"
+ integrity sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==
+ dependencies:
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+ "@lezer/highlight" "^1.0.0"
+
+"@codemirror/view@^6.0.0", "@codemirror/view@^6.17.0", "@codemirror/view@^6.23.0", "@codemirror/view@^6.27.0":
+ version "6.28.2"
+ resolved "https://registry.yarnpkg.com/@codemirror/view/-/view-6.28.2.tgz#026d5d2bd315aa015c1a1573b6358eeba7acd004"
+ integrity sha512-A3DmyVfjgPsGIjiJqM/zvODUAPQdQl3ci0ghehYNnbt5x+o76xq+dL5+mMBuysDXnI3kapgOkoeJ0sbtL/3qPw==
+ dependencies:
+ "@codemirror/state" "^6.4.0"
+ style-mod "^4.1.0"
+ w3c-keyname "^2.2.4"
+
+"@colors/colors@1.5.0":
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
+ integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
+
+"@colors/colors@1.6.0", "@colors/colors@^1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.6.0.tgz#ec6cd237440700bc23ca23087f513c75508958b0"
+ integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==
+
+"@dabh/diagnostics@^2.0.2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a"
+ integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==
+ dependencies:
+ colorspace "1.1.x"
+ enabled "2.0.x"
+ kuler "^2.0.0"
+
+"@discoveryjs/json-ext@0.5.7":
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70"
+ integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==
+
+"@emotion/babel-plugin@^11.11.0":
+ version "11.11.0"
+ resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c"
+ integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==
+ dependencies:
+ "@babel/helper-module-imports" "^7.16.7"
+ "@babel/runtime" "^7.18.3"
+ "@emotion/hash" "^0.9.1"
+ "@emotion/memoize" "^0.8.1"
+ "@emotion/serialize" "^1.1.2"
+ babel-plugin-macros "^3.1.0"
+ convert-source-map "^1.5.0"
+ escape-string-regexp "^4.0.0"
+ find-root "^1.1.0"
+ source-map "^0.5.7"
+ stylis "4.2.0"
+
+"@emotion/cache@^11.11.0", "@emotion/cache@^11.4.0":
+ version "11.11.0"
+ resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff"
+ integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==
+ dependencies:
+ "@emotion/memoize" "^0.8.1"
+ "@emotion/sheet" "^1.2.2"
+ "@emotion/utils" "^1.2.1"
+ "@emotion/weak-memoize" "^0.3.1"
+ stylis "4.2.0"
+
+"@emotion/hash@^0.9.1":
+ version "0.9.1"
+ resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
+ integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==
+
+"@emotion/is-prop-valid@^0.8.8":
+ version "0.8.8"
+ resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz#db28b1c4368a259b60a97311d6a952d4fd01ac1a"
+ integrity sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==
+ dependencies:
+ "@emotion/memoize" "0.7.4"
+
+"@emotion/memoize@0.7.4":
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.4.tgz#19bf0f5af19149111c40d98bb0cf82119f5d9eeb"
+ integrity sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==
+
+"@emotion/memoize@^0.8.1":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17"
+ integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
+
+"@emotion/react@^11.8.1":
+ version "11.11.4"
+ resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.4.tgz#3a829cac25c1f00e126408fab7f891f00ecc3c1d"
+ integrity sha512-t8AjMlF0gHpvvxk5mAtCqR4vmxiGHCeJBaQO6gncUSdklELOgtwjerNY2yuJNfwnc6vi16U/+uMF+afIawJ9iw==
+ dependencies:
+ "@babel/runtime" "^7.18.3"
+ "@emotion/babel-plugin" "^11.11.0"
+ "@emotion/cache" "^11.11.0"
+ "@emotion/serialize" "^1.1.3"
+ "@emotion/use-insertion-effect-with-fallbacks" "^1.0.1"
+ "@emotion/utils" "^1.2.1"
+ "@emotion/weak-memoize" "^0.3.1"
+ hoist-non-react-statics "^3.3.1"
+
+"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3":
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451"
+ integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==
+ dependencies:
+ "@emotion/hash" "^0.9.1"
+ "@emotion/memoize" "^0.8.1"
+ "@emotion/unitless" "^0.8.1"
+ "@emotion/utils" "^1.2.1"
+ csstype "^3.0.2"
+
+"@emotion/sheet@^1.2.2":
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec"
+ integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==
+
+"@emotion/stylis@^0.8.4":
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/@emotion/stylis/-/stylis-0.8.5.tgz#deacb389bd6ee77d1e7fcaccce9e16c5c7e78e04"
+ integrity sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==
+
+"@emotion/unitless@^0.7.4":
+ version "0.7.5"
+ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed"
+ integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
+
+"@emotion/unitless@^0.8.1":
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3"
+ integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==
+
+"@emotion/use-insertion-effect-with-fallbacks@^1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963"
+ integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==
+
+"@emotion/utils@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4"
+ integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==
+
+"@emotion/weak-memoize@^0.3.1":
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6"
+ integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==
+
+"@esbuild/aix-ppc64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3"
+ integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==
+
+"@esbuild/aix-ppc64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz#d1bc06aedb6936b3b6d313bf809a5a40387d2b7f"
+ integrity sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==
+
+"@esbuild/aix-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f"
+ integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==
+
+"@esbuild/android-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
+ integrity sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==
+
+"@esbuild/android-arm64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz#b45d000017385c9051a4f03e17078abb935be220"
+ integrity sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==
+
+"@esbuild/android-arm64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz#7ad65a36cfdb7e0d429c353e00f680d737c2aed4"
+ integrity sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==
+
+"@esbuild/android-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052"
+ integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==
+
+"@esbuild/android-arm@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.16.17.tgz#025b6246d3f68b7bbaa97069144fb5fb70f2fff2"
+ integrity sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==
+
+"@esbuild/android-arm@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz#f46f55414e1c3614ac682b29977792131238164c"
+ integrity sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==
+
+"@esbuild/android-arm@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.12.tgz#b0c26536f37776162ca8bde25e42040c203f2824"
+ integrity sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==
+
+"@esbuild/android-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28"
+ integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==
+
+"@esbuild/android-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.16.17.tgz#c820e0fef982f99a85c4b8bfdd582835f04cd96e"
+ integrity sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==
+
+"@esbuild/android-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz#bfc01e91740b82011ef503c48f548950824922b2"
+ integrity sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==
+
+"@esbuild/android-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.12.tgz#cb13e2211282012194d89bf3bfe7721273473b3d"
+ integrity sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==
+
+"@esbuild/android-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e"
+ integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==
+
+"@esbuild/darwin-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.17.tgz#edef4487af6b21afabba7be5132c26d22379b220"
+ integrity sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==
+
+"@esbuild/darwin-arm64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz#533fb7f5a08c37121d82c66198263dcc1bed29bf"
+ integrity sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==
+
+"@esbuild/darwin-arm64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz#cbee41e988020d4b516e9d9e44dd29200996275e"
+ integrity sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==
+
+"@esbuild/darwin-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a"
+ integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==
+
+"@esbuild/darwin-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.16.17.tgz#42829168730071c41ef0d028d8319eea0e2904b4"
+ integrity sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==
+
+"@esbuild/darwin-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz#62f3819eff7e4ddc656b7c6815a31cf9a1e7d98e"
+ integrity sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==
+
+"@esbuild/darwin-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz#e37d9633246d52aecf491ee916ece709f9d5f4cd"
+ integrity sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==
+
+"@esbuild/darwin-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22"
+ integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==
+
+"@esbuild/freebsd-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.17.tgz#1f4af488bfc7e9ced04207034d398e793b570a27"
+ integrity sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==
+
+"@esbuild/freebsd-arm64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a"
+ integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==
+
+"@esbuild/freebsd-arm64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz#1ee4d8b682ed363b08af74d1ea2b2b4dbba76487"
+ integrity sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==
+
+"@esbuild/freebsd-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e"
+ integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==
+
+"@esbuild/freebsd-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.17.tgz#636306f19e9bc981e06aa1d777302dad8fddaf72"
+ integrity sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==
+
+"@esbuild/freebsd-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz#7bdcc1917409178257ca6a1a27fe06e797ec18a2"
+ integrity sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==
+
+"@esbuild/freebsd-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz#37a693553d42ff77cd7126764b535fb6cc28a11c"
+ integrity sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==
+
+"@esbuild/freebsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261"
+ integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==
+
+"@esbuild/linux-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.16.17.tgz#a003f7ff237c501e095d4f3a09e58fc7b25a4aca"
+ integrity sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==
+
+"@esbuild/linux-arm64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545"
+ integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==
+
+"@esbuild/linux-arm64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz#be9b145985ec6c57470e0e051d887b09dddb2d4b"
+ integrity sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==
+
+"@esbuild/linux-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b"
+ integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==
+
+"@esbuild/linux-arm@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.16.17.tgz#b591e6a59d9c4fe0eeadd4874b157ab78cf5f196"
+ integrity sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==
+
+"@esbuild/linux-arm@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz#ce82246d873b5534d34de1e5c1b33026f35e60e3"
+ integrity sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==
+
+"@esbuild/linux-arm@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz#207ecd982a8db95f7b5279207d0ff2331acf5eef"
+ integrity sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==
+
+"@esbuild/linux-arm@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9"
+ integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==
+
+"@esbuild/linux-ia32@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.16.17.tgz#24333a11027ef46a18f57019450a5188918e2a54"
+ integrity sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==
+
+"@esbuild/linux-ia32@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4"
+ integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==
+
+"@esbuild/linux-ia32@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz#d0d86b5ca1562523dc284a6723293a52d5860601"
+ integrity sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==
+
+"@esbuild/linux-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2"
+ integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==
+
+"@esbuild/linux-loong64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.16.17.tgz#d5ad459d41ed42bbd4d005256b31882ec52227d8"
+ integrity sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==
+
+"@esbuild/linux-loong64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121"
+ integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==
+
+"@esbuild/linux-loong64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz#9a37f87fec4b8408e682b528391fa22afd952299"
+ integrity sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==
+
+"@esbuild/linux-loong64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df"
+ integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==
+
+"@esbuild/linux-mips64el@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.17.tgz#4e5967a665c38360b0a8205594377d4dcf9c3726"
+ integrity sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==
+
+"@esbuild/linux-mips64el@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz#38eecf1cbb8c36a616261de858b3c10d03419af9"
+ integrity sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==
+
+"@esbuild/linux-mips64el@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz#4ddebd4e6eeba20b509d8e74c8e30d8ace0b89ec"
+ integrity sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==
+
+"@esbuild/linux-mips64el@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe"
+ integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==
+
+"@esbuild/linux-ppc64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.17.tgz#206443a02eb568f9fdf0b438fbd47d26e735afc8"
+ integrity sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==
+
+"@esbuild/linux-ppc64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912"
+ integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==
+
+"@esbuild/linux-ppc64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz#adb67dadb73656849f63cd522f5ecb351dd8dee8"
+ integrity sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==
+
+"@esbuild/linux-ppc64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4"
+ integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==
+
+"@esbuild/linux-riscv64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.17.tgz#c351e433d009bf256e798ad048152c8d76da2fc9"
+ integrity sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==
+
+"@esbuild/linux-riscv64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz#2dc4486d474a2a62bbe5870522a9a600e2acb916"
+ integrity sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==
+
+"@esbuild/linux-riscv64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz#11bc0698bf0a2abf8727f1c7ace2112612c15adf"
+ integrity sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==
+
+"@esbuild/linux-riscv64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc"
+ integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==
+
+"@esbuild/linux-s390x@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.16.17.tgz#661f271e5d59615b84b6801d1c2123ad13d9bd87"
+ integrity sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==
+
+"@esbuild/linux-s390x@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8"
+ integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==
+
+"@esbuild/linux-s390x@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz#e86fb8ffba7c5c92ba91fc3b27ed5a70196c3cc8"
+ integrity sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==
+
+"@esbuild/linux-s390x@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de"
+ integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==
+
+"@esbuild/linux-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.16.17.tgz#e4ba18e8b149a89c982351443a377c723762b85f"
+ integrity sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==
+
+"@esbuild/linux-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766"
+ integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==
+
+"@esbuild/linux-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz#5f37cfdc705aea687dfe5dfbec086a05acfe9c78"
+ integrity sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==
+
+"@esbuild/linux-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0"
+ integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==
+
+"@esbuild/netbsd-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.17.tgz#7d4f4041e30c5c07dd24ffa295c73f06038ec775"
+ integrity sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==
+
+"@esbuild/netbsd-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz#d633c09492a1721377f3bccedb2d821b911e813d"
+ integrity sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==
+
+"@esbuild/netbsd-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz#29da566a75324e0d0dd7e47519ba2f7ef168657b"
+ integrity sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==
+
+"@esbuild/netbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047"
+ integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==
+
+"@esbuild/openbsd-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.17.tgz#970fa7f8470681f3e6b1db0cc421a4af8060ec35"
+ integrity sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==
+
+"@esbuild/openbsd-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2"
+ integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==
+
+"@esbuild/openbsd-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz#306c0acbdb5a99c95be98bdd1d47c916e7dc3ff0"
+ integrity sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==
+
+"@esbuild/openbsd-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70"
+ integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==
+
+"@esbuild/sunos-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.16.17.tgz#abc60e7c4abf8b89fb7a4fe69a1484132238022c"
+ integrity sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==
+
+"@esbuild/sunos-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767"
+ integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==
+
+"@esbuild/sunos-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz#0933eaab9af8b9b2c930236f62aae3fc593faf30"
+ integrity sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==
+
+"@esbuild/sunos-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b"
+ integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==
+
+"@esbuild/win32-arm64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.16.17.tgz#7b0ff9e8c3265537a7a7b1fd9a24e7bd39fcd87a"
+ integrity sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==
+
+"@esbuild/win32-arm64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee"
+ integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==
+
+"@esbuild/win32-arm64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz#773bdbaa1971b36db2f6560088639ccd1e6773ae"
+ integrity sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==
+
+"@esbuild/win32-arm64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d"
+ integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==
+
+"@esbuild/win32-ia32@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.16.17.tgz#e90fe5267d71a7b7567afdc403dfd198c292eb09"
+ integrity sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==
+
+"@esbuild/win32-ia32@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz#481a65fee2e5cce74ec44823e6b09ecedcc5194c"
+ integrity sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==
+
+"@esbuild/win32-ia32@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz#000516cad06354cc84a73f0943a4aa690ef6fd67"
+ integrity sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==
+
+"@esbuild/win32-ia32@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b"
+ integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==
+
+"@esbuild/win32-x64@0.16.17":
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.16.17.tgz#c5a1a4bfe1b57f0c3e61b29883525c6da3e5c091"
+ integrity sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==
+
+"@esbuild/win32-x64@0.19.11":
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04"
+ integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==
+
+"@esbuild/win32-x64@0.19.12":
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz#c57c8afbb4054a3ab8317591a0b7320360b444ae"
+ integrity sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==
+
+"@esbuild/win32-x64@0.21.5":
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c"
+ integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==
+
+"@floating-ui/core@^1.0.0":
+ version "1.6.2"
+ resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.6.2.tgz#d37f3e0ac1f1c756c7de45db13303a266226851a"
+ integrity sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==
+ dependencies:
+ "@floating-ui/utils" "^0.2.0"
+
+"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.0.1":
+ version "1.6.5"
+ resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.6.5.tgz#323f065c003f1d3ecf0ff16d2c2c4d38979f4cb9"
+ integrity sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==
+ dependencies:
+ "@floating-ui/core" "^1.0.0"
+ "@floating-ui/utils" "^0.2.0"
+
+"@floating-ui/react-dom@^2.0.0", "@floating-ui/react-dom@^2.0.8":
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.1.0.tgz#4f0e5e9920137874b2405f7d6c862873baf4beff"
+ integrity sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==
+ dependencies:
+ "@floating-ui/dom" "^1.0.0"
+
+"@floating-ui/utils@^0.2.0":
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.2.tgz#d8bae93ac8b815b2bd7a98078cf91e2724ef11e5"
+ integrity sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==
+
+"@formatjs/ecma402-abstract@1.14.3":
+ version "1.14.3"
+ resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.14.3.tgz#6428f243538a11126180d121ce8d4b2f17465738"
+ integrity sha512-SlsbRC/RX+/zg4AApWIFNDdkLtFbkq3LNoZWXZCE/nHVKqoIJyaoQyge/I0Y38vLxowUn9KTtXgusLD91+orbg==
+ dependencies:
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/fast-memoize@2.0.1":
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.0.1.tgz#f15aaa73caad5562899c69bdcad8db82adcd3b0b"
+ integrity sha512-M2GgV+qJn5WJQAYewz7q2Cdl6fobQa69S1AzSM2y0P68ZDbK5cWrJIcPCO395Of1ksftGZoOt4LYCO/j9BKBSA==
+ dependencies:
+ tslib "^2.4.0"
+
+"@formatjs/icu-messageformat-parser@2.3.1":
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.3.1.tgz#953080ea5c053bc73bdf55d0a524a3c3c133ae6b"
+ integrity sha512-knF2AkAKN4Upv4oIiKY4Wd/dLH68TNMPgV/tJMu/T6FP9aQwbv8fpj7U3lkyniPaNVxvia56Gxax8MKOjtxLSQ==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/icu-skeleton-parser" "1.3.18"
+ tslib "^2.4.0"
+
+"@formatjs/icu-skeleton-parser@1.3.18":
+ version "1.3.18"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.18.tgz#7aed3d60e718c8ad6b0e64820be44daa1e29eeeb"
+ integrity sha512-ND1ZkZfmLPcHjAH1sVpkpQxA+QYfOX3py3SjKWMUVGDow18gZ0WPqz3F+pJLYQMpS2LnnQ5zYR2jPVYTbRwMpg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ tslib "^2.4.0"
+
+"@formatjs/intl-displaynames@6.3.1":
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.3.1.tgz#6dcea7cb801460e2a8fa63eb38c54aa1b24f92c0"
+ integrity sha512-TlxguMDUbnFrJ4NA8fSyqXC62M7czvlRJ5mrJgtB91JVA+QPjjNdcRm1qPIC/DcU/pGUDcEzThn/x5A+jp15gg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/intl-listformat@7.2.1":
+ version "7.2.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.2.1.tgz#874eddc7d53ba2e3fd911bf30efc459fc99f08db"
+ integrity sha512-fRJFWLrGa7d25I4JSxNjKX29oXGcIXx8fJjgURnvs2C3ijS4gurUgFrUwLbv/2KfPfyJ5g567pz2INelNJZBdw==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/intl-localematcher" "0.2.32"
+ tslib "^2.4.0"
+
+"@formatjs/intl-localematcher@0.2.32":
+ version "0.2.32"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.32.tgz#00d4d307cd7d514b298e15a11a369b86c8933ec1"
+ integrity sha512-k/MEBstff4sttohyEpXxCmC3MqbUn9VvHGlZ8fauLzkbwXmVrEeyzS+4uhrvAk9DWU9/7otYWxyDox4nT/KVLQ==
+ dependencies:
+ tslib "^2.4.0"
+
+"@formatjs/intl@2.7.1":
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.7.1.tgz#f7e052ff09e9fe019ad83d4139af0de40084a2ae"
+ integrity sha512-se6vxidsN3PCmzqTsDd3YDT4IX9ZySPy39LYhF7x2ssNvlGMOuW3umkrIhKkXB7ZskqsJGY53LVCdiHsSwhGng==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/fast-memoize" "2.0.1"
+ "@formatjs/icu-messageformat-parser" "2.3.1"
+ "@formatjs/intl-displaynames" "6.3.1"
+ "@formatjs/intl-listformat" "7.2.1"
+ intl-messageformat "10.3.4"
+ tslib "^2.4.0"
+
+"@graphql-typed-document-node/core@^3.2.0":
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
+ integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
+
+"@hapi/bourne@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@hapi/bourne/-/bourne-3.0.0.tgz#f11fdf7dda62fe8e336fa7c6642d9041f30356d7"
+ integrity sha512-Waj1cwPXJDucOib4a3bAISsKJVb15MKi9IvmTI/7ssVEm6sywXGjVJDhl6/umt1pK1ZS7PacXU3A1PmFKHEZ2w==
+
+"@human-protocol/core@*", "@human-protocol/core@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@human-protocol/core/-/core-3.0.0.tgz#3825034f1d95446cf50c3f84d4f6a7a571cc6f54"
+ integrity sha512-IjcA+avEnmLbgyV+6nw2QmpG2KGyKH5gRRhr/NgR6Y7FeuGdFLcJ3es4oGQDYrBcsjwmrTedVLYsVRT0OtD6AQ==
+
+"@human-protocol/sdk@^3.0.0":
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/@human-protocol/sdk/-/sdk-3.0.0.tgz#0d2da8a41df24aee268fbac85b075557fff9c95e"
+ integrity sha512-5ny/+/oYEiXTllDlq0N2R/aniFsoJa36krQX3KzLv4wQU/OPZOAzmL9+WRaSS6QA/TclkqPVmOwNHt+6ucL2BA==
+ dependencies:
+ "@human-protocol/core" "*"
+ aws-sdk "^2.1528.0"
+ axios "^1.4.0"
+ graphql "^16.8.1"
+ graphql-request "^6.1.0"
+ graphql-tag "^2.12.6"
+ minio "7.1.3"
+ openpgp "^5.11.1"
+ secp256k1 "^4.0.3"
+ vitest "^1.6.0"
+ winston "^3.13.0"
+
+"@internationalized/date@^3.5.2":
+ version "3.5.4"
+ resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.5.4.tgz#49ba11634fd4350b7a9308e297032267b4063c44"
+ integrity sha512-qoVJVro+O0rBaw+8HPjUB1iH8Ihf8oziEnqMnvhJUSuVIrHOuZ6eNLHNvzXJKUvAtaDiqMnRlg8Z2mgh09BlUw==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@internationalized/number@^3.5.1":
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.5.3.tgz#9fa060c1c4809f23fb3d38dd3f3d1ae4c87e95a8"
+ integrity sha512-rd1wA3ebzlp0Mehj5YTuTI50AQEx80gWFyHcQu+u91/5NgdwBecO8BH6ipPfE+lmQ9d63vpB3H9SHoIUiupllw==
+ dependencies:
+ "@swc/helpers" "^0.5.0"
+
+"@isaacs/cliui@^8.0.2":
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
+ integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
+ dependencies:
+ string-width "^5.1.2"
+ string-width-cjs "npm:string-width@^4.2.0"
+ strip-ansi "^7.0.1"
+ strip-ansi-cjs "npm:strip-ansi@^6.0.1"
+ wrap-ansi "^8.1.0"
+ wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
+
+"@isaacs/fs-minipass@^4.0.0":
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz#2d59ae3ab4b38fb4270bfa23d30f8e2e86c7fe32"
+ integrity sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==
+ dependencies:
+ minipass "^7.0.4"
+
+"@jest/schemas@^29.6.3":
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03"
+ integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==
+ dependencies:
+ "@sinclair/typebox" "^0.27.8"
+
+"@jridgewell/gen-mapping@^0.3.5":
+ version "0.3.5"
+ resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
+ integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
+ dependencies:
+ "@jridgewell/set-array" "^1.2.1"
+ "@jridgewell/sourcemap-codec" "^1.4.10"
+ "@jridgewell/trace-mapping" "^0.3.24"
+
+"@jridgewell/resolve-uri@^3.1.0":
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
+ integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
+
+"@jridgewell/set-array@^1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
+ integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
+
+"@jridgewell/source-map@^0.3.3":
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a"
+ integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==
+ dependencies:
+ "@jridgewell/gen-mapping" "^0.3.5"
+ "@jridgewell/trace-mapping" "^0.3.25"
+
+"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15":
+ version "1.4.15"
+ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+ integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
+"@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
+ version "0.3.25"
+ resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
+ integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
+ dependencies:
+ "@jridgewell/resolve-uri" "^3.1.0"
+ "@jridgewell/sourcemap-codec" "^1.4.14"
+
+"@juggle/resize-observer@^3.4.0":
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
+ integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
+
+"@koa/cors@5.0.0":
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-5.0.0.tgz#0029b5f057fa0d0ae0e37dd2c89ece315a0daffd"
+ integrity sha512-x/iUDjcS90W69PryLDIMgFyV21YLTnG9zOpPXS7Bkt2b8AsY3zZsIpOLBkYr9fBcF3HbkKaER5hOBZLfpLgYNw==
+ dependencies:
+ vary "^1.1.2"
+
+"@koa/router@10.1.1":
+ version "10.1.1"
+ resolved "https://registry.yarnpkg.com/@koa/router/-/router-10.1.1.tgz#8e5a85c9b243e0bc776802c0de564561e57a5f78"
+ integrity sha512-ORNjq5z4EmQPriKbR0ER3k4Gh7YGNhWDL7JBW+8wXDrHLbWYKYSJaOJ9aN06npF5tbTxe2JBOsurpJDAvjiXKw==
+ dependencies:
+ debug "^4.1.1"
+ http-errors "^1.7.3"
+ koa-compose "^4.1.0"
+ methods "^1.1.2"
+ path-to-regexp "^6.1.0"
+
+"@lezer/common@^1.0.0", "@lezer/common@^1.1.0", "@lezer/common@^1.2.0":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.1.tgz#198b278b7869668e1bebbe687586e12a42731049"
+ integrity sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==
+
+"@lezer/highlight@^1.0.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.0.tgz#e5898c3644208b4b589084089dceeea2966f7780"
+ integrity sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==
+ dependencies:
+ "@lezer/common" "^1.0.0"
+
+"@lezer/json@^1.0.0":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@lezer/json/-/json-1.0.2.tgz#bdc849e174113e2d9a569a5e6fb1a27e2f703eaf"
+ integrity sha512-xHT2P4S5eeCYECyKNPhr4cbEL9tc8w83SPwRC373o9uEdrvGKTZoJVAGxpOsZckMlEh9W23Pc72ew918RWQOBQ==
+ dependencies:
+ "@lezer/common" "^1.2.0"
+ "@lezer/highlight" "^1.0.0"
+ "@lezer/lr" "^1.0.0"
+
+"@lezer/lr@^1.0.0":
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.1.tgz#fe25f051880a754e820b28148d90aa2a96b8bdd2"
+ integrity sha512-CHsKq8DMKBf9b3yXPDIU4DbH+ZJd/sJdYOW2llbW/HudP5u0VS6Bfq1hLYfgU7uAYGFIyGGQIsSOXGPEErZiJw==
+ dependencies:
+ "@lezer/common" "^1.0.0"
+
+"@noble/curves@1.2.0", "@noble/curves@~1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.2.0.tgz#92d7e12e4e49b23105a2555c6984d41733d65c35"
+ integrity sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==
+ dependencies:
+ "@noble/hashes" "1.3.2"
+
+"@noble/hashes@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39"
+ integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==
+
+"@noble/hashes@~1.3.0", "@noble/hashes@~1.3.2":
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699"
+ integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==
+
+"@nodelib/fs.scandir@2.1.5":
+ version "2.1.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
+ integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
+ integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
+
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
+ integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ fastq "^1.6.0"
+
+"@pkgjs/parseargs@^0.11.0":
+ version "0.11.0"
+ resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
+ integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
+
+"@pkgr/utils@^2.3.1":
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc"
+ integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw==
+ dependencies:
+ cross-spawn "^7.0.3"
+ fast-glob "^3.3.0"
+ is-glob "^4.0.3"
+ open "^9.1.0"
+ picocolors "^1.0.0"
+ tslib "^2.6.0"
+
+"@pmmmwh/react-refresh-webpack-plugin@0.5.11":
+ version "0.5.11"
+ resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.5.11.tgz#7c2268cedaa0644d677e8c4f377bc8fb304f714a"
+ integrity sha512-7j/6vdTym0+qZ6u4XbSAxrWBGYSdCfTzySkj7WAFgDLmSyWlOrWvpyzxlFh5jtw9dn0oL/jtW+06XfFiisN3JQ==
+ dependencies:
+ ansi-html-community "^0.0.8"
+ common-path-prefix "^3.0.0"
+ core-js-pure "^3.23.3"
+ error-stack-parser "^2.0.6"
+ find-up "^5.0.0"
+ html-entities "^2.1.0"
+ loader-utils "^2.0.4"
+ schema-utils "^3.0.0"
+ source-map "^0.7.3"
+
+"@pnpm/config.env-replace@^1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz#ab29da53df41e8948a00f2433f085f54de8b3a4c"
+ integrity sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==
+
+"@pnpm/network.ca-file@^1.0.1":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz#2ab05e09c1af0cdf2fcf5035bea1484e222f7983"
+ integrity sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==
+ dependencies:
+ graceful-fs "4.2.10"
+
+"@pnpm/npm-conf@^2.1.0":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz#0058baf1c26cbb63a828f0193795401684ac86f0"
+ integrity sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==
+ dependencies:
+ "@pnpm/config.env-replace" "^1.1.0"
+ "@pnpm/network.ca-file" "^1.0.1"
+ config-chain "^1.1.11"
+
+"@polka/url@^1.0.0-next.24":
+ version "1.0.0-next.25"
+ resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817"
+ integrity sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==
+
+"@radix-ui/number@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.1.0.tgz#1e95610461a09cdf8bb05c152e76ca1278d5da46"
+ integrity sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==
+
+"@radix-ui/primitive@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.0.1.tgz#e46f9958b35d10e9f6dc71c497305c22e3e55dbd"
+ integrity sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/primitive@1.1.0", "@radix-ui/primitive@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2"
+ integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==
+
+"@radix-ui/react-arrow@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz#744f388182d360b86285217e43b6c63633f39e7a"
+ integrity sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==
+ dependencies:
+ "@radix-ui/react-primitive" "2.0.0"
+
+"@radix-ui/react-collection@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.0.3.tgz#9595a66e09026187524a36c6e7e9c7d286469159"
+ integrity sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-slot" "1.0.2"
+
+"@radix-ui/react-collection@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-1.1.0.tgz#f18af78e46454a2360d103c2251773028b7724ed"
+ integrity sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-context" "1.1.0"
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-slot" "1.1.0"
+
+"@radix-ui/react-compose-refs@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989"
+ integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-compose-refs@1.1.0", "@radix-ui/react-compose-refs@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74"
+ integrity sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==
+
+"@radix-ui/react-context@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.1.tgz#fe46e67c96b240de59187dcb7a1a50ce3e2ec00c"
+ integrity sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-context@1.1.0", "@radix-ui/react-context@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8"
+ integrity sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==
+
+"@radix-ui/react-direction@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.0.1.tgz#9cb61bf2ccf568f3421422d182637b7f47596c9b"
+ integrity sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-direction@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-direction/-/react-direction-1.1.0.tgz#a7d39855f4d077adc2a1922f9c353c5977a09cdc"
+ integrity sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==
+
+"@radix-ui/react-dismissable-layer@1.1.0", "@radix-ui/react-dismissable-layer@^1.0.5":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz#2cd0a49a732372513733754e6032d3fb7988834e"
+ integrity sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==
+ dependencies:
+ "@radix-ui/primitive" "1.1.0"
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-use-callback-ref" "1.1.0"
+ "@radix-ui/react-use-escape-keydown" "1.1.0"
+
+"@radix-ui/react-dropdown-menu@^2.0.6":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz#3dc578488688250dbbe109d9ff2ca28a9bca27ec"
+ integrity sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==
+ dependencies:
+ "@radix-ui/primitive" "1.1.0"
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-context" "1.1.0"
+ "@radix-ui/react-id" "1.1.0"
+ "@radix-ui/react-menu" "2.1.1"
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-use-controllable-state" "1.1.0"
+
+"@radix-ui/react-focus-guards@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.0.1.tgz#1ea7e32092216b946397866199d892f71f7f98ad"
+ integrity sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-focus-guards@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz#8e9abb472a9a394f59a1b45f3dd26cfe3fc6da13"
+ integrity sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==
+
+"@radix-ui/react-focus-scope@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.0.4.tgz#2ac45fce8c5bb33eb18419cdc1905ef4f1906525"
+ integrity sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+
+"@radix-ui/react-focus-scope@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz#ebe2891a298e0a33ad34daab2aad8dea31caf0b2"
+ integrity sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-use-callback-ref" "1.1.0"
+
+"@radix-ui/react-id@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.0.1.tgz#73cdc181f650e4df24f0b6a5b7aa426b912c88c0"
+ integrity sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+
+"@radix-ui/react-id@1.1.0", "@radix-ui/react-id@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.0.tgz#de47339656594ad722eb87f94a6b25f9cffae0ed"
+ integrity sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==
+ dependencies:
+ "@radix-ui/react-use-layout-effect" "1.1.0"
+
+"@radix-ui/react-menu@2.1.1":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-2.1.1.tgz#bd623ace0e1ae1ac78023a505fec0541d59fb346"
+ integrity sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==
+ dependencies:
+ "@radix-ui/primitive" "1.1.0"
+ "@radix-ui/react-collection" "1.1.0"
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-context" "1.1.0"
+ "@radix-ui/react-direction" "1.1.0"
+ "@radix-ui/react-dismissable-layer" "1.1.0"
+ "@radix-ui/react-focus-guards" "1.1.0"
+ "@radix-ui/react-focus-scope" "1.1.0"
+ "@radix-ui/react-id" "1.1.0"
+ "@radix-ui/react-popper" "1.2.0"
+ "@radix-ui/react-portal" "1.1.1"
+ "@radix-ui/react-presence" "1.1.0"
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-roving-focus" "1.1.0"
+ "@radix-ui/react-slot" "1.1.0"
+ "@radix-ui/react-use-callback-ref" "1.1.0"
+ aria-hidden "^1.1.1"
+ react-remove-scroll "2.5.7"
+
+"@radix-ui/react-popper@1.2.0", "@radix-ui/react-popper@^1.1.3":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-1.2.0.tgz#a3e500193d144fe2d8f5d5e60e393d64111f2a7a"
+ integrity sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==
+ dependencies:
+ "@floating-ui/react-dom" "^2.0.0"
+ "@radix-ui/react-arrow" "1.1.0"
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-context" "1.1.0"
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-use-callback-ref" "1.1.0"
+ "@radix-ui/react-use-layout-effect" "1.1.0"
+ "@radix-ui/react-use-rect" "1.1.0"
+ "@radix-ui/react-use-size" "1.1.0"
+ "@radix-ui/rect" "1.1.0"
+
+"@radix-ui/react-portal@1.1.1", "@radix-ui/react-portal@^1.0.4":
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.1.tgz#1957f1eb2e1aedfb4a5475bd6867d67b50b1d15f"
+ integrity sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==
+ dependencies:
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-use-layout-effect" "1.1.0"
+
+"@radix-ui/react-presence@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.0.tgz#227d84d20ca6bfe7da97104b1a8b48a833bfb478"
+ integrity sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-use-layout-effect" "1.1.0"
+
+"@radix-ui/react-primitive@1.0.3", "@radix-ui/react-primitive@^1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-1.0.3.tgz#d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0"
+ integrity sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-slot" "1.0.2"
+
+"@radix-ui/react-primitive@2.0.0":
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz#fe05715faa9203a223ccc0be15dc44b9f9822884"
+ integrity sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==
+ dependencies:
+ "@radix-ui/react-slot" "1.1.0"
+
+"@radix-ui/react-roving-focus@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.0.4.tgz#e90c4a6a5f6ac09d3b8c1f5b5e81aab2f0db1974"
+ integrity sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-id" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
+"@radix-ui/react-roving-focus@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz#b30c59daf7e714c748805bfe11c76f96caaac35e"
+ integrity sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==
+ dependencies:
+ "@radix-ui/primitive" "1.1.0"
+ "@radix-ui/react-collection" "1.1.0"
+ "@radix-ui/react-compose-refs" "1.1.0"
+ "@radix-ui/react-context" "1.1.0"
+ "@radix-ui/react-direction" "1.1.0"
+ "@radix-ui/react-id" "1.1.0"
+ "@radix-ui/react-primitive" "2.0.0"
+ "@radix-ui/react-use-callback-ref" "1.1.0"
+ "@radix-ui/react-use-controllable-state" "1.1.0"
+
+"@radix-ui/react-separator@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-separator/-/react-separator-1.0.3.tgz#be5a931a543d5726336b112f465f58585c04c8aa"
+ integrity sha512-itYmTy/kokS21aiV5+Z56MZB54KrhPgn6eHDKkFeOLR34HMN2s8PaN47qZZAGnvupcjxHaFZnW4pQEh0BvvVuw==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-primitive" "1.0.3"
+
+"@radix-ui/react-slot@1.0.2":
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab"
+ integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-compose-refs" "1.0.1"
+
+"@radix-ui/react-slot@1.1.0", "@radix-ui/react-slot@^1.0.2":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84"
+ integrity sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==
+ dependencies:
+ "@radix-ui/react-compose-refs" "1.1.0"
+
+"@radix-ui/react-toggle-group@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle-group/-/react-toggle-group-1.0.4.tgz#f5b5c8c477831b013bec3580c55e20a68179d6ec"
+ integrity sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-roving-focus" "1.0.4"
+ "@radix-ui/react-toggle" "1.0.3"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
+"@radix-ui/react-toggle@1.0.3":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toggle/-/react-toggle-1.0.3.tgz#aecb2945630d1dc5c512997556c57aba894e539e"
+ integrity sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-use-controllable-state" "1.0.1"
+
+"@radix-ui/react-toolbar@1.0.4":
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-toolbar/-/react-toolbar-1.0.4.tgz#3211a105567fa016e89921b5b514877f833de559"
+ integrity sha512-tBgmM/O7a07xbaEkYJWYTXkIdU/1pW4/KZORR43toC/4XWyBCURK0ei9kMUdp+gTPPKBgYLxXmRSH1EVcIDp8Q==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/primitive" "1.0.1"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-primitive" "1.0.3"
+ "@radix-ui/react-roving-focus" "1.0.4"
+ "@radix-ui/react-separator" "1.0.3"
+ "@radix-ui/react-toggle-group" "1.0.4"
+
+"@radix-ui/react-use-callback-ref@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.1.tgz#f4bb1f27f2023c984e6534317ebc411fc181107a"
+ integrity sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-use-callback-ref@1.1.0", "@radix-ui/react-use-callback-ref@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz#bce938ca413675bc937944b0d01ef6f4a6dc5bf1"
+ integrity sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==
+
+"@radix-ui/react-use-controllable-state@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.0.1.tgz#ecd2ced34e6330caf89a82854aa2f77e07440286"
+ integrity sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+ "@radix-ui/react-use-callback-ref" "1.0.1"
+
+"@radix-ui/react-use-controllable-state@1.1.0", "@radix-ui/react-use-controllable-state@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz#1321446857bb786917df54c0d4d084877aab04b0"
+ integrity sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==
+ dependencies:
+ "@radix-ui/react-use-callback-ref" "1.1.0"
+
+"@radix-ui/react-use-escape-keydown@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz#31a5b87c3b726504b74e05dac1edce7437b98754"
+ integrity sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==
+ dependencies:
+ "@radix-ui/react-use-callback-ref" "1.1.0"
+
+"@radix-ui/react-use-layout-effect@1.0.1":
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.0.1.tgz#be8c7bc809b0c8934acf6657b577daf948a75399"
+ integrity sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==
+ dependencies:
+ "@babel/runtime" "^7.13.10"
+
+"@radix-ui/react-use-layout-effect@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz#3c2c8ce04827b26a39e442ff4888d9212268bd27"
+ integrity sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==
+
+"@radix-ui/react-use-previous@^1.0.1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-1.1.0.tgz#d4dd37b05520f1d996a384eb469320c2ada8377c"
+ integrity sha512-Z/e78qg2YFnnXcW88A4JmTtm4ADckLno6F7OXotmkQfeuCVaKuYzqAATPhVzl3delXE7CxIV8shofPn3jPc5Og==
+
+"@radix-ui/react-use-rect@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz#13b25b913bd3e3987cc9b073a1a164bb1cf47b88"
+ integrity sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==
+ dependencies:
+ "@radix-ui/rect" "1.1.0"
+
+"@radix-ui/react-use-size@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz#b4dba7fbd3882ee09e8d2a44a3eed3a7e555246b"
+ integrity sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==
+ dependencies:
+ "@radix-ui/react-use-layout-effect" "1.1.0"
+
+"@radix-ui/react-visually-hidden@^1.0.3":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.1.0.tgz#ad47a8572580f7034b3807c8e6740cd41038a5a2"
+ integrity sha512-N8MDZqtgCgG5S3aV60INAB475osJousYpZ4cTJ2cFbMpdHS5Y6loLTH8LPtkj2QN0x93J30HT/M3qJXM0+lyeQ==
+ dependencies:
+ "@radix-ui/react-primitive" "2.0.0"
+
+"@radix-ui/rect@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-1.1.0.tgz#f817d1d3265ac5415dadc67edab30ae196696438"
+ integrity sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg==
+
+"@react-dnd/asap@^5.0.1":
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-5.0.2.tgz#1f81f124c1cd6f39511c11a881cfb0f715343488"
+ integrity sha512-WLyfoHvxhs0V9U+GTsGilGgf2QsPl6ZZ44fnv0/b8T3nQyvzxidxsg/ZltbWssbsRDlYW8UKSQMTGotuTotZ6A==
+
+"@react-dnd/invariant@^4.0.1":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-4.0.2.tgz#b92edffca10a26466643349fac7cdfb8799769df"
+ integrity sha512-xKCTqAK/FFauOM9Ta2pswIyT3D8AQlfrYdOi/toTPEhqCuAs1v5tcJ3Y08Izh1cJ5Jchwy9SeAXmMg6zrKs2iw==
+
+"@react-dnd/shallowequal@^4.0.1":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-4.0.2.tgz#d1b4befa423f692fa4abf1c79209702e7d8ae4b4"
+ integrity sha512-/RVXdLvJxLg4QKvMoM5WlwNR9ViO9z8B/qPcc+C0Sa/teJY7QG7kJ441DwzOjMYEY7GmU4dj5EcGHIkKZiQZCA==
+
+"@reduxjs/toolkit@1.9.7":
+ version "1.9.7"
+ resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.7.tgz#7fc07c0b0ebec52043f8cb43510cf346405f78a6"
+ integrity sha512-t7v8ZPxhhKgOKtU+uyJT13lu4vL7az5aFi4IdoDs/eS548edn2M8Ik9h8fxgvMjGoAUVFSt6ZC1P5cWmQ014QQ==
+ dependencies:
+ immer "^9.0.21"
+ redux "^4.2.1"
+ redux-thunk "^2.4.2"
+ reselect "^4.1.8"
+
+"@rollup/rollup-android-arm-eabi@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz#bbd0e616b2078cd2d68afc9824d1fadb2f2ffd27"
+ integrity sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==
+
+"@rollup/rollup-android-arm64@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz#97255ef6384c5f73f4800c0de91f5f6518e21203"
+ integrity sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==
+
+"@rollup/rollup-darwin-arm64@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz#b6dd74e117510dfe94541646067b0545b42ff096"
+ integrity sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==
+
+"@rollup/rollup-darwin-x64@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz#e07d76de1cec987673e7f3d48ccb8e106d42c05c"
+ integrity sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==
+
+"@rollup/rollup-linux-arm-gnueabihf@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz#9f1a6d218b560c9d75185af4b8bb42f9f24736b8"
+ integrity sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==
+
+"@rollup/rollup-linux-arm-musleabihf@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz#53618b92e6ffb642c7b620e6e528446511330549"
+ integrity sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==
+
+"@rollup/rollup-linux-arm64-gnu@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz#99a7ba5e719d4f053761a698f7b52291cefba577"
+ integrity sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==
+
+"@rollup/rollup-linux-arm64-musl@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz#f53db99a45d9bc00ce94db8a35efa7c3c144a58c"
+ integrity sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==
+
+"@rollup/rollup-linux-powerpc64le-gnu@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz#cbb0837408fe081ce3435cf3730e090febafc9bf"
+ integrity sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==
+
+"@rollup/rollup-linux-riscv64-gnu@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz#8ed09c1d1262ada4c38d791a28ae0fea28b80cc9"
+ integrity sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==
+
+"@rollup/rollup-linux-s390x-gnu@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz#938138d3c8e0c96f022252a28441dcfb17afd7ec"
+ integrity sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==
+
+"@rollup/rollup-linux-x64-gnu@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz#1a7481137a54740bee1ded4ae5752450f155d942"
+ integrity sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==
+
+"@rollup/rollup-linux-x64-musl@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz#f1186afc601ac4f4fc25fac4ca15ecbee3a1874d"
+ integrity sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==
+
+"@rollup/rollup-win32-arm64-msvc@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz#ed6603e93636a96203c6915be4117245c1bd2daf"
+ integrity sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==
+
+"@rollup/rollup-win32-ia32-msvc@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz#14e0b404b1c25ebe6157a15edb9c46959ba74c54"
+ integrity sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==
+
+"@rollup/rollup-win32-x64-msvc@4.18.0":
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz#5d694d345ce36b6ecf657349e03eb87297e68da4"
+ integrity sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==
+
+"@rushstack/node-core-library@5.4.1":
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-5.4.1.tgz#3d7fe919a2ca0e84fd1410a3700f6a2e49950d20"
+ integrity sha512-WNnwdS8r9NZ/2K3u29tNoSRldscFa7SxU0RT+82B6Dy2I4Hl2MeCSKm4EXLXPKeNzLGvJ1cqbUhTLviSF8E6iA==
+ dependencies:
+ ajv "~8.13.0"
+ ajv-draft-04 "~1.0.0"
+ ajv-formats "~3.0.1"
+ fs-extra "~7.0.1"
+ import-lazy "~4.0.0"
+ jju "~1.4.0"
+ resolve "~1.22.1"
+ semver "~7.5.4"
+
+"@rushstack/terminal@0.13.0":
+ version "0.13.0"
+ resolved "https://registry.yarnpkg.com/@rushstack/terminal/-/terminal-0.13.0.tgz#623c454e77e2f1ad530b680e25627d8902dcd1be"
+ integrity sha512-Ou44Q2s81BqJu3dpYedAX54am9vn245F0HzqVrfJCMQk5pGgoKKOBOjkbfZC9QKcGNaECh6pwH2s5noJt7X6ew==
+ dependencies:
+ "@rushstack/node-core-library" "5.4.1"
+ supports-color "~8.1.1"
+
+"@rushstack/ts-command-line@^4.12.2":
+ version "4.22.0"
+ resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-4.22.0.tgz#5725f923d1663f4cfe97a121b2fbc11d7cd488c3"
+ integrity sha512-Qj28t6MO3HRgAZ72FDeFsrpdE6wBWxF3VENgvrXh7JF2qIT+CrXiOJIesW80VFZB9QwObSpkB1ilx794fGQg6g==
+ dependencies:
+ "@rushstack/terminal" "0.13.0"
+ "@types/argparse" "1.0.38"
+ argparse "~1.0.9"
+ string-argv "~0.3.1"
+
+"@scure/base@~1.1.0", "@scure/base@~1.1.2":
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.7.tgz#fe973311a5c6267846aa131bc72e96c5d40d2b30"
+ integrity sha512-PPNYBslrLNNUQ/Yad37MHYsNQtK67EhWb6WtSvNLLPo7SdVZgkUjD6Dg+5On7zNwmskf8OX7I7Nx5oN+MIWE0g==
+
+"@scure/bip32@1.3.2":
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/@scure/bip32/-/bip32-1.3.2.tgz#90e78c027d5e30f0b22c1f8d50ff12f3fb7559f8"
+ integrity sha512-N1ZhksgwD3OBlwTv3R6KFEcPojl/W4ElJOeCZdi+vuI5QmTFwLq3OFf2zd2ROpKvxFdgZ6hUpb0dx9bVNEwYCA==
+ dependencies:
+ "@noble/curves" "~1.2.0"
+ "@noble/hashes" "~1.3.2"
+ "@scure/base" "~1.1.2"
+
+"@scure/bip39@1.2.1":
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/@scure/bip39/-/bip39-1.2.1.tgz#5cee8978656b272a917b7871c981e0541ad6ac2a"
+ integrity sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==
+ dependencies:
+ "@noble/hashes" "~1.3.0"
+ "@scure/base" "~1.1.0"
+
+"@sentry/core@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.19.7.tgz#156aaa56dd7fad8c89c145be6ad7a4f7209f9785"
+ integrity sha512-tOfZ/umqB2AcHPGbIrsFLcvApdTm9ggpi/kQZFkej7kMphjT+SGBiQfYtjyg9jcRW+ilAR4JXC9BGKsdEQ+8Vw==
+ dependencies:
+ "@sentry/hub" "6.19.7"
+ "@sentry/minimal" "6.19.7"
+ "@sentry/types" "6.19.7"
+ "@sentry/utils" "6.19.7"
+ tslib "^1.9.3"
+
+"@sentry/hub@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.19.7.tgz#58ad7776bbd31e9596a8ec46365b45cd8b9cfd11"
+ integrity sha512-y3OtbYFAqKHCWezF0EGGr5lcyI2KbaXW2Ik7Xp8Mu9TxbSTuwTe4rTntwg8ngPjUQU3SUHzgjqVB8qjiGqFXCA==
+ dependencies:
+ "@sentry/types" "6.19.7"
+ "@sentry/utils" "6.19.7"
+ tslib "^1.9.3"
+
+"@sentry/minimal@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.19.7.tgz#b3ee46d6abef9ef3dd4837ebcb6bdfd01b9aa7b4"
+ integrity sha512-wcYmSJOdvk6VAPx8IcmZgN08XTXRwRtB1aOLZm+MVHjIZIhHoBGZJYTVQS/BWjldsamj2cX3YGbGXNunaCfYJQ==
+ dependencies:
+ "@sentry/hub" "6.19.7"
+ "@sentry/types" "6.19.7"
+ tslib "^1.9.3"
+
+"@sentry/node@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.19.7.tgz#32963b36b48daebbd559e6f13b1deb2415448592"
+ integrity sha512-gtmRC4dAXKODMpHXKfrkfvyBL3cI8y64vEi3fDD046uqYcrWdgoQsffuBbxMAizc6Ez1ia+f0Flue6p15Qaltg==
+ dependencies:
+ "@sentry/core" "6.19.7"
+ "@sentry/hub" "6.19.7"
+ "@sentry/types" "6.19.7"
+ "@sentry/utils" "6.19.7"
+ cookie "^0.4.1"
+ https-proxy-agent "^5.0.0"
+ lru_map "^0.3.3"
+ tslib "^1.9.3"
+
+"@sentry/types@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.19.7.tgz#c6b337912e588083fc2896eb012526cf7cfec7c7"
+ integrity sha512-jH84pDYE+hHIbVnab3Hr+ZXr1v8QABfhx39KknxqKWr2l0oEItzepV0URvbEhB446lk/S/59230dlUUIBGsXbg==
+
+"@sentry/utils@6.19.7":
+ version "6.19.7"
+ resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.19.7.tgz#6edd739f8185fd71afe49cbe351c1bbf5e7b7c79"
+ integrity sha512-z95ECmE3i9pbWoXQrD/7PgkBAzJYR+iXtPuTkpBjDKs86O3mT+PXOT3BAn79w2wkn7/i3vOGD2xVr1uiMl26dA==
+ dependencies:
+ "@sentry/types" "6.19.7"
+ tslib "^1.9.3"
+
+"@simov/deep-extend@^1.0.0":
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/@simov/deep-extend/-/deep-extend-1.0.0.tgz#dff17d38305614e296eb80bf4898b9d10b061325"
+ integrity sha512-Arv8/ZPcdKAMJnNF8cks35mPq1y3JnwH1lWpfWDKlJoj+Vw2xmA4+oL7m9GVHTgdX0mGFR7bCPTBTGbxhnfJJw==
+
+"@sinclair/typebox@^0.27.8":
+ version "0.27.8"
+ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e"
+ integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==
+
+"@sindresorhus/is@^4.0.0":
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f"
+ integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==
+
+"@sindresorhus/slugify@1.1.0":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/slugify/-/slugify-1.1.0.tgz#2f195365d9b953384305b62664b44b4036c49430"
+ integrity sha512-ujZRbmmizX26yS/HnB3P9QNlNa4+UvHh+rIse3RbOXLp8yl6n1TxB4t7NHggtVgS8QmmOtzXo48kCxZGACpkPw==
+ dependencies:
+ "@sindresorhus/transliterate" "^0.1.1"
+ escape-string-regexp "^4.0.0"
+
+"@sindresorhus/transliterate@^0.1.1":
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/@sindresorhus/transliterate/-/transliterate-0.1.2.tgz#ffce368271d153550e87de81486004f2637425af"
+ integrity sha512-5/kmIOY9FF32nicXH+5yLNTX4NJ4atl7jRgqAJuIn/iyDFXBktOKDxCvyGE/EzmF4ngSUvjXxQUQlQiZ5lfw+w==
+ dependencies:
+ escape-string-regexp "^2.0.0"
+ lodash.deburr "^4.1.0"
+
+"@strapi/admin@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/admin/-/admin-4.25.1.tgz#ad07b86fb7d356e326f4a3a464b94e2130471388"
+ integrity sha512-e63UVE9SQA1ggCGK7U4Z37SzLirLmEJERTrhaPkPBg2SkYwUgYSMRVZlgwjmEthOtmwFLG8J6qOtklzltN8FYA==
+ dependencies:
+ "@casl/ability" "6.5.0"
+ "@pmmmwh/react-refresh-webpack-plugin" "0.5.11"
+ "@radix-ui/react-context" "1.0.1"
+ "@radix-ui/react-toolbar" "1.0.4"
+ "@reduxjs/toolkit" "1.9.7"
+ "@strapi/design-system" "1.19.0"
+ "@strapi/helper-plugin" "4.25.1"
+ "@strapi/icons" "1.19.0"
+ "@strapi/permissions" "4.25.1"
+ "@strapi/provider-audit-logs-local" "4.25.1"
+ "@strapi/types" "4.25.1"
+ "@strapi/typescript-utils" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ "@vitejs/plugin-react-swc" "3.5.0"
+ axios "1.6.0"
+ bcryptjs "2.4.3"
+ boxen "5.1.2"
+ browserslist "^4.22.2"
+ browserslist-to-esbuild "1.2.0"
+ chalk "^4.1.2"
+ chokidar "3.5.3"
+ codemirror5 "npm:codemirror@^5.65.11"
+ cross-env "^7.0.3"
+ css-loader "^6.9.0"
+ date-fns "2.30.0"
+ dotenv "14.2.0"
+ esbuild "0.19.11"
+ esbuild-loader "^2.21.0"
+ esbuild-register "3.5.0"
+ execa "5.1.1"
+ fast-deep-equal "3.1.3"
+ find-root "1.1.0"
+ fork-ts-checker-webpack-plugin "9.0.2"
+ formik "2.4.0"
+ fractional-indexing "3.2.0"
+ fs-extra "10.0.0"
+ highlight.js "^10.4.1"
+ history "^4.9.0"
+ html-webpack-plugin "5.6.0"
+ immer "9.0.19"
+ inquirer "8.2.5"
+ invariant "^2.2.4"
+ js-cookie "2.2.1"
+ jsonwebtoken "9.0.0"
+ koa "2.13.4"
+ koa-bodyparser "4.4.1"
+ koa-compose "4.1.0"
+ koa-passport "5.0.0"
+ koa-static "5.0.0"
+ koa2-ratelimit "^1.1.2"
+ lodash "4.17.21"
+ markdown-it "^12.3.2"
+ markdown-it-abbr "^1.0.4"
+ markdown-it-container "^3.0.0"
+ markdown-it-deflist "^2.1.0"
+ markdown-it-emoji "^2.0.0"
+ markdown-it-footnote "^3.0.3"
+ markdown-it-ins "^3.0.1"
+ markdown-it-mark "^3.0.1"
+ markdown-it-sub "^1.0.0"
+ markdown-it-sup "1.0.0"
+ mini-css-extract-plugin "2.7.7"
+ node-schedule "2.1.0"
+ ora "5.4.1"
+ outdent "0.8.0"
+ p-map "4.0.0"
+ passport-local "1.0.0"
+ pluralize "8.0.0"
+ prettier "2.8.4"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react-dnd "16.0.1"
+ react-dnd-html5-backend "16.0.1"
+ react-error-boundary "3.1.4"
+ react-helmet "^6.1.0"
+ react-intl "6.4.1"
+ react-is "^18.2.0"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ react-refresh "0.14.0"
+ react-select "5.7.0"
+ react-window "1.8.8"
+ read-pkg-up "7.0.1"
+ resolve-from "5.0.0"
+ rimraf "3.0.2"
+ sanitize-html "2.13.0"
+ semver "7.5.4"
+ sift "16.0.1"
+ slate "0.94.1"
+ slate-history "0.93.0"
+ slate-react "0.98.3"
+ style-loader "3.3.4"
+ typescript "5.2.2"
+ vite "5.0.13"
+ webpack "^5.89.0"
+ webpack-bundle-analyzer "^4.10.1"
+ webpack-dev-middleware "6.1.2"
+ webpack-hot-middleware "2.26.0"
+ yup "0.32.9"
+
+"@strapi/cloud-cli@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/cloud-cli/-/cloud-cli-4.25.1.tgz#2ac4697b1cdd810aa1c06f02af917abd19d6c66d"
+ integrity sha512-5S6Dz3LAH4nlm37P/C+pMyOBvt0+LSea0DB0usd1RTA4rVv/chURrIW+qNEDztGabt3Co8PgWIPF1m+LgSO8pQ==
+ dependencies:
+ "@strapi/utils" "4.25.1"
+ axios "1.6.0"
+ chalk "4.1.2"
+ cli-progress "3.12.0"
+ commander "8.3.0"
+ eventsource "2.0.2"
+ fast-safe-stringify "2.1.1"
+ fs-extra "10.0.0"
+ inquirer "8.2.5"
+ jsonwebtoken "9.0.0"
+ jwks-rsa "3.1.0"
+ lodash "4.17.21"
+ minimatch "9.0.3"
+ open "8.4.0"
+ ora "5.4.1"
+ pkg-up "3.1.0"
+ tar "6.1.13"
+ xdg-app-paths "8.3.0"
+ yup "0.32.9"
+
+"@strapi/content-releases@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/content-releases/-/content-releases-4.25.1.tgz#c8ca2741e2b2b6c3544d799c193df49dd68cc45c"
+ integrity sha512-HpXcNkS3XWyfghXlnFPYFbonSs3+SM8HnoKrzki5U+6WTpe6mi2A/EYR2h/+L1r8HTB2H1cs+2J54b5OspNvzA==
+ dependencies:
+ "@reduxjs/toolkit" "1.9.7"
+ "@strapi/design-system" "1.19.0"
+ "@strapi/helper-plugin" "4.25.1"
+ "@strapi/icons" "1.19.0"
+ "@strapi/types" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ axios "1.6.0"
+ date-fns "2.30.0"
+ date-fns-tz "2.0.0"
+ formik "2.4.0"
+ lodash "4.17.21"
+ node-schedule "2.1.0"
+ react-intl "6.4.1"
+ react-redux "8.1.1"
+ yup "0.32.9"
+
+"@strapi/data-transfer@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/data-transfer/-/data-transfer-4.25.1.tgz#24453588fc07f014a1990c39d721234ca6077f10"
+ integrity sha512-vu23DfwY4gVQg79MHViBA2mHoTcnt5n4E+9QvW6WyeFiRMXnu1pv7JwDxYXudhQh24j/1GqGI6PIjnovdewisw==
+ dependencies:
+ "@strapi/logger" "4.25.1"
+ "@strapi/strapi" "4.25.1"
+ "@strapi/types" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ chalk "4.1.2"
+ cli-table3 "0.6.2"
+ commander "8.3.0"
+ fs-extra "10.0.0"
+ inquirer "8.2.5"
+ lodash "4.17.21"
+ ora "5.4.1"
+ resolve-cwd "3.0.0"
+ semver "7.5.4"
+ stream-chain "2.2.5"
+ stream-json "1.8.0"
+ tar "6.1.13"
+ tar-stream "2.2.0"
+ ws "8.13.0"
+
+"@strapi/database@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/database/-/database-4.25.1.tgz#91cdee6ace3e8ace563c4db21bd91426be46a955"
+ integrity sha512-pkapnhmIUFau+NrF4rJAoImCBJElgXmYyVqz+8Zz2JMjyyDwtDTBu9OIQEo6AXuDU8bf1Q+knv1ejEETwKD30A==
+ dependencies:
+ "@strapi/utils" "4.25.1"
+ date-fns "2.30.0"
+ debug "4.3.4"
+ fs-extra "10.0.0"
+ knex "2.5.0"
+ lodash "4.17.21"
+ semver "7.5.4"
+ umzug "3.2.1"
+
+"@strapi/design-system@1.19.0":
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/@strapi/design-system/-/design-system-1.19.0.tgz#1b0ca923c22f167baa6d35663e7f47c971df474c"
+ integrity sha512-kEQNaRztIcr6I5Zh6mxtE/Nmkk1mylCS5s56ySKDdqOjWZw2BCbS72/J9k6r1RF1TLIDSXJN9r5dHR0ZKtWvBQ==
+ dependencies:
+ "@codemirror/lang-json" "^6.0.1"
+ "@floating-ui/react-dom" "^2.0.8"
+ "@internationalized/date" "^3.5.2"
+ "@internationalized/number" "^3.5.1"
+ "@radix-ui/react-dismissable-layer" "^1.0.5"
+ "@radix-ui/react-dropdown-menu" "^2.0.6"
+ "@radix-ui/react-focus-scope" "1.0.4"
+ "@strapi/ui-primitives" "^1.19.0"
+ "@uiw/react-codemirror" "^4.21.25"
+ aria-hidden "^1.2.4"
+ compute-scroll-into-view "^3.1.0"
+ prop-types "^15.8.1"
+ react-remove-scroll "^2.5.9"
+
+"@strapi/generate-new@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/generate-new/-/generate-new-4.25.1.tgz#df066c0c3c79daba1040e20f56f80f66bb1af2fd"
+ integrity sha512-k4qp6muCVpdUl8hmGLN444PWMirXaYEmjbuIB7h30+Z9TBO03XqWYqK20yX6u4Y8Jjpc8/WkIyFQ9GDCPL8V7Q==
+ dependencies:
+ "@sentry/node" "6.19.7"
+ chalk "^4.1.2"
+ execa "5.1.1"
+ fs-extra "10.0.0"
+ inquirer "8.2.5"
+ lodash "4.17.21"
+ node-fetch "2.7.0"
+ node-machine-id "^1.1.10"
+ ora "^5.4.1"
+ semver "7.5.4"
+ tar "6.1.13"
+
+"@strapi/generators@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/generators/-/generators-4.25.1.tgz#5ae4bc1318fa0832bc3505555f6dc2bd8979b8a3"
+ integrity sha512-rfQ3+tWwLDJBjt/Q3PuHyrjlzPAkQOrDi3s6CirXPzrpZMX9QDZzzf0PIZiKthEsP9vQYbmppe2FOU4YRB8uIQ==
+ dependencies:
+ "@sindresorhus/slugify" "1.1.0"
+ "@strapi/typescript-utils" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ chalk "4.1.2"
+ copyfiles "2.4.1"
+ fs-extra "10.0.0"
+ node-plop "0.26.3"
+ plop "2.7.6"
+ pluralize "8.0.0"
+
+"@strapi/helper-plugin@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/helper-plugin/-/helper-plugin-4.25.1.tgz#2f286c537ff1fa7baaacbbfb8a5bac0b26143da0"
+ integrity sha512-mBWwKjh2OmvwvUPECaRcNf6+IicE6D3OqtlqFXzQsJqHw5Dv6l6WFFh2/rEsjK93Qh5xAkvHqxaRNYJF2QIBFg==
+ dependencies:
+ axios "1.6.0"
+ date-fns "2.30.0"
+ formik "2.4.0"
+ immer "9.0.19"
+ lodash "4.17.21"
+ qs "6.11.1"
+ react-helmet "6.1.0"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-select "5.7.0"
+
+"@strapi/icons@1.19.0":
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/@strapi/icons/-/icons-1.19.0.tgz#efa6b553a7de437171512e3549859faa141a145f"
+ integrity sha512-jcS7n3Ps+73fYGadxdaD6owazoDJKN1fHSG9dp8RX4RqkP6BfoHOX5j3aodVLmDX57Ksg6gy5JXf9xEml7nMpQ==
+
+"@strapi/logger@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/logger/-/logger-4.25.1.tgz#b3ed814972ba5f3fb7812db3e6406fb9fbf1e79f"
+ integrity sha512-sDY1goEbqXxtrMIyMGmYysSrehRsHhTekDA4KjmbYHWbE3D6G38zA0jU9kstCr3pixO4nZ67hw5wWrJTeOhj2A==
+ dependencies:
+ lodash "4.17.21"
+ winston "3.10.0"
+
+"@strapi/pack-up@4.23.0":
+ version "4.23.0"
+ resolved "https://registry.yarnpkg.com/@strapi/pack-up/-/pack-up-4.23.0.tgz#c75f985a370f47414d9643545ee8e26c486b3711"
+ integrity sha512-hiSqUEEzks2JDai6bfvtvPHYaPhI6UnSifx9ZqBdC9Q551BYm1xt+1K7HJVeW0IPI4zLckZvCcGPHh/NeYyTPw==
+ dependencies:
+ "@vitejs/plugin-react-swc" "3.5.0"
+ boxen "5.1.2"
+ browserslist-to-esbuild "1.2.0"
+ chalk "4.1.2"
+ chokidar "3.5.3"
+ commander "8.3.0"
+ esbuild "0.19.11"
+ esbuild-register "3.5.0"
+ get-latest-version "5.1.0"
+ git-url-parse "13.1.0"
+ ini "4.1.1"
+ ora "5.4.1"
+ outdent "0.8.0"
+ pkg-up "3.1.0"
+ prettier "2.8.4"
+ prettier-plugin-packagejson "2.4.5"
+ prompts "2.4.2"
+ rxjs "7.8.1"
+ typescript "5.2.2"
+ vite "5.0.13"
+ yup "0.32.9"
+
+"@strapi/permissions@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/permissions/-/permissions-4.25.1.tgz#1faf4dbedb5e763a4abc02e634468c9502e3327b"
+ integrity sha512-PPpRMSC8fOyRv0PJK62T67woo6SILKlJQk+cMmC3CYZpFlUYkmSU5EufSD8Znx56j0XsATvvJ98IQ/3hveAEIg==
+ dependencies:
+ "@casl/ability" "6.5.0"
+ "@strapi/utils" "4.25.1"
+ lodash "4.17.21"
+ qs "6.11.1"
+ sift "16.0.1"
+
+"@strapi/plugin-content-manager@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-content-manager/-/plugin-content-manager-4.25.1.tgz#d1576f4aa88d300caa36648530cb99dc59417de0"
+ integrity sha512-WqOXfhKN6L09PBcSmMS6burof4VHOAK24RWTrMcazgidA57GZ003lqW5dw2ashJ71s2p3YU83lzKVxztoswboQ==
+ dependencies:
+ "@sindresorhus/slugify" "1.1.0"
+ "@strapi/types" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ koa "2.13.4"
+ koa-bodyparser "4.4.1"
+ lodash "4.17.21"
+ qs "6.11.1"
+
+"@strapi/plugin-content-type-builder@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-content-type-builder/-/plugin-content-type-builder-4.25.1.tgz#cb3dae6167b946bea5408cbbdf0683a2f59410f2"
+ integrity sha512-mWpRjiXoVlbSEnQ6ANRLiDloZTP14hDH5Mrc2mP2plgBl/zqm/QgE9sifaDUh6cqqTDV2+UWFvCGuT+1JqyGwQ==
+ dependencies:
+ "@reduxjs/toolkit" "1.9.7"
+ "@sindresorhus/slugify" "1.1.0"
+ "@strapi/design-system" "1.19.0"
+ "@strapi/generators" "4.25.1"
+ "@strapi/helper-plugin" "4.25.1"
+ "@strapi/icons" "1.19.0"
+ "@strapi/utils" "4.25.1"
+ fs-extra "10.0.0"
+ immer "9.0.19"
+ koa-bodyparser "4.4.1"
+ lodash "4.17.21"
+ pluralize "8.0.0"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react-helmet "^6.1.0"
+ react-intl "6.4.1"
+ react-redux "8.1.1"
+ yup "0.32.9"
+
+"@strapi/plugin-email@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-email/-/plugin-email-4.25.1.tgz#faca02b55d1352592d9b37a8db05e97a4abd7dfa"
+ integrity sha512-VESF5M97hFsrdToW7rsrkpbOZqnT7C8RH8Z9MgYokxk3lJ/LJwpFLypB8X52QnK9XmdR8wNAbZgm+rxyPOmSvA==
+ dependencies:
+ "@strapi/design-system" "1.19.0"
+ "@strapi/helper-plugin" "4.25.1"
+ "@strapi/icons" "1.19.0"
+ "@strapi/provider-email-sendmail" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ lodash "4.17.21"
+ prop-types "^15.8.1"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ yup "0.32.9"
+
+"@strapi/plugin-i18n@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-i18n/-/plugin-i18n-4.25.1.tgz#d7ea242f6f58b51ecea4ea37c8537e5b9cb79ed3"
+ integrity sha512-nzKRwnliUnkvi7Z5FtA/ldQlFfFGcuGkKhGc9Z3D0D3bZFoOm5wQf8Q+jyQ8sWPv7yBXLF+mv68QpoB8pmGr9g==
+ dependencies:
+ "@reduxjs/toolkit" "1.9.7"
+ "@strapi/design-system" "1.19.0"
+ "@strapi/helper-plugin" "4.25.1"
+ "@strapi/icons" "1.19.0"
+ "@strapi/utils" "4.25.1"
+ axios "1.6.0"
+ formik "2.4.0"
+ immer "9.0.19"
+ lodash "4.17.21"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ yup "0.32.9"
+
+"@strapi/plugin-upload@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-upload/-/plugin-upload-4.25.1.tgz#714e43274d7006d17f43ce9ec1219e0dad8fa12b"
+ integrity sha512-0wfEJldvRTyvNIqEM/FKojnlQcFlt/+GAhn/OyPqbS66e0fbCvzugEvIi/mRhx+jmLc25lJMazSjFZ/ELZxFCQ==
+ dependencies:
+ "@strapi/design-system" "1.19.0"
+ "@strapi/helper-plugin" "4.25.1"
+ "@strapi/icons" "1.19.0"
+ "@strapi/provider-upload-local" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ axios "1.6.0"
+ byte-size "7.0.1"
+ cropperjs "1.6.0"
+ date-fns "2.30.0"
+ formik "2.4.0"
+ fs-extra "10.0.0"
+ immer "9.0.19"
+ koa-range "0.3.0"
+ koa-static "5.0.0"
+ lodash "4.17.21"
+ mime-types "2.1.35"
+ prop-types "^15.8.1"
+ qs "6.11.1"
+ react-dnd "16.0.1"
+ react-helmet "^6.1.0"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ react-select "5.7.0"
+ sharp "0.32.6"
+ yup "0.32.9"
+
+"@strapi/plugin-users-permissions@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/plugin-users-permissions/-/plugin-users-permissions-4.25.1.tgz#20d43655086a49386a4698fe2a390e902cb9f4af"
+ integrity sha512-jTrsy1GSEU0mkuOwKvaSfKo8ow0NuWYIJljptC45AnyVFt0L0duej61EhrMci1xe0235teeN7K6WshF6lFdrPw==
+ dependencies:
+ "@strapi/design-system" "1.19.0"
+ "@strapi/helper-plugin" "4.25.1"
+ "@strapi/icons" "1.19.0"
+ "@strapi/utils" "4.25.1"
+ bcryptjs "2.4.3"
+ formik "2.4.0"
+ grant-koa "5.4.8"
+ immer "9.0.19"
+ jsonwebtoken "9.0.0"
+ jwk-to-pem "2.0.5"
+ koa "2.13.4"
+ koa2-ratelimit "^1.1.2"
+ lodash "4.17.21"
+ prop-types "^15.8.1"
+ purest "4.0.2"
+ react-intl "6.4.1"
+ react-query "3.39.3"
+ react-redux "8.1.1"
+ url-join "4.0.1"
+ yup "0.32.9"
+
+"@strapi/provider-audit-logs-local@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-audit-logs-local/-/provider-audit-logs-local-4.25.1.tgz#e99e4a590aa4b205febd7f1d222942d00e1129ec"
+ integrity sha512-R1wdAMgW15q4rG3PD6tT1fI5Jf+/eP5uhnT0nEZIH2ws1rJ/r8A4qk0hCAUYH1OUR1xVn+3oJ/xqln26MPLA/Q==
+
+"@strapi/provider-email-sendmail@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-email-sendmail/-/provider-email-sendmail-4.25.1.tgz#39a51ae6c203884bffb06b6730b4c1ce9efdc3a1"
+ integrity sha512-eKp912Q0nIZOKEivgOpyFV9OAurNU+oJV/00eh9Q2uDWdtSl/Z7pO481XyFan7Jthn7aB2J5C50xzhQrsFaggA==
+ dependencies:
+ "@strapi/utils" "4.25.1"
+ sendmail "^1.6.1"
+
+"@strapi/provider-upload-local@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/provider-upload-local/-/provider-upload-local-4.25.1.tgz#10d2e4946797186240ca1841790eb02bbe6b9c96"
+ integrity sha512-jkTfHfFPwE5PMWvU/yUHfyv9rI5D+OcUVtzKFmkkVs/l6T6UAWSWh+26kZYJ4fpotfNWX6XNHtgtvQXS+08uVw==
+ dependencies:
+ "@strapi/utils" "4.25.1"
+ fs-extra "10.0.0"
+
+"@strapi/strapi@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/strapi/-/strapi-4.25.1.tgz#3871f1786249ad65a2a8cafbc660c3320a53eeae"
+ integrity sha512-GzsIArE/jkK78v7w/gQXQ02lfb1cnb0qyvTUotSOwh9FzZhV+nGURkNYvlSooyEtDxOIimD1RnkRP11iOW0kHA==
+ dependencies:
+ "@koa/cors" "5.0.0"
+ "@koa/router" "10.1.1"
+ "@strapi/admin" "4.25.1"
+ "@strapi/cloud-cli" "4.25.1"
+ "@strapi/content-releases" "4.25.1"
+ "@strapi/data-transfer" "4.25.1"
+ "@strapi/database" "4.25.1"
+ "@strapi/generate-new" "4.25.1"
+ "@strapi/generators" "4.25.1"
+ "@strapi/logger" "4.25.1"
+ "@strapi/pack-up" "4.23.0"
+ "@strapi/permissions" "4.25.1"
+ "@strapi/plugin-content-manager" "4.25.1"
+ "@strapi/plugin-content-type-builder" "4.25.1"
+ "@strapi/plugin-email" "4.25.1"
+ "@strapi/plugin-upload" "4.25.1"
+ "@strapi/types" "4.25.1"
+ "@strapi/typescript-utils" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ bcryptjs "2.4.3"
+ boxen "5.1.2"
+ chalk "4.1.2"
+ ci-info "3.8.0"
+ cli-progress "3.12.0"
+ cli-table3 "0.6.2"
+ commander "8.3.0"
+ concurrently "8.2.2"
+ configstore "5.0.1"
+ copyfiles "2.4.1"
+ debug "4.3.4"
+ delegates "1.0.0"
+ dotenv "14.2.0"
+ execa "5.1.1"
+ fs-extra "10.0.0"
+ get-latest-version "5.1.0"
+ git-url-parse "13.1.0"
+ glob "7.2.3"
+ http-errors "1.8.1"
+ https-proxy-agent "5.0.1"
+ inquirer "8.2.5"
+ is-docker "2.2.1"
+ koa "2.13.4"
+ koa-body "4.2.0"
+ koa-compose "4.1.0"
+ koa-compress "5.1.0"
+ koa-favicon "2.1.0"
+ koa-helmet "7.0.2"
+ koa-ip "^2.1.2"
+ koa-session "6.4.0"
+ koa-static "5.0.0"
+ lodash "4.17.21"
+ mime-types "2.1.35"
+ node-fetch "2.7.0"
+ node-machine-id "1.1.12"
+ node-schedule "2.1.0"
+ nodemon "3.0.2"
+ open "8.4.0"
+ ora "5.4.1"
+ outdent "0.8.0"
+ package-json "7.0.0"
+ pkg-up "3.1.0"
+ qs "6.11.1"
+ semver "7.5.4"
+ statuses "2.0.1"
+ typescript "5.2.2"
+ yalc "1.0.0-pre.53"
+ yup "0.32.9"
+
+"@strapi/types@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/types/-/types-4.25.1.tgz#669d81b79b247c9a1d2bf731970036d402447e9d"
+ integrity sha512-Sr89A4LiQQN6p5jnMbfarknJ6KUr2Hp8fd2QNtOXLRwyrL3sPEZYlm7JRr2QoK0fT2QRh83iKdYsiA18J33Qww==
+ dependencies:
+ "@casl/ability" "6.5.0"
+ "@koa/cors" "5.0.0"
+ "@koa/router" "10.1.1"
+ "@strapi/database" "4.25.1"
+ "@strapi/logger" "4.25.1"
+ "@strapi/permissions" "4.25.1"
+ "@strapi/utils" "4.25.1"
+ commander "8.3.0"
+ https-proxy-agent "5.0.1"
+ koa "2.13.4"
+ node-fetch "2.7.0"
+ node-schedule "2.1.0"
+
+"@strapi/typescript-utils@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/typescript-utils/-/typescript-utils-4.25.1.tgz#37327dc39b883f67b2192ab40be00c94d93d1ee7"
+ integrity sha512-hXu3rxHaNH+FUCYar1vj6mTdIvMstkPhfo1+AOusdLtsSWVPA7+J5+dB4IKtjM72MVU0hiF3Q63SR6BCcsdC0Q==
+ dependencies:
+ chalk "4.1.2"
+ cli-table3 "0.6.2"
+ fs-extra "10.0.0"
+ lodash "4.17.21"
+ prettier "2.8.4"
+ typescript "5.2.2"
+
+"@strapi/ui-primitives@^1.19.0":
+ version "1.19.0"
+ resolved "https://registry.yarnpkg.com/@strapi/ui-primitives/-/ui-primitives-1.19.0.tgz#01e2709d64bbde1f6810c49898da216934f76479"
+ integrity sha512-dEpmI0PpSH6VWuP/bBvRKI5lUpazdDAcxOpukoq2QDwUFbuZWywgW7a6O5nMnD4bLQtyNeYwd52J8Jqr9pNoQA==
+ dependencies:
+ "@radix-ui/number" "^1.0.1"
+ "@radix-ui/primitive" "^1.0.1"
+ "@radix-ui/react-collection" "1.0.3"
+ "@radix-ui/react-compose-refs" "^1.0.1"
+ "@radix-ui/react-context" "^1.0.1"
+ "@radix-ui/react-direction" "1.0.1"
+ "@radix-ui/react-dismissable-layer" "^1.0.5"
+ "@radix-ui/react-focus-guards" "1.0.1"
+ "@radix-ui/react-focus-scope" "1.0.4"
+ "@radix-ui/react-id" "^1.0.1"
+ "@radix-ui/react-popper" "^1.1.3"
+ "@radix-ui/react-portal" "^1.0.4"
+ "@radix-ui/react-primitive" "^1.0.3"
+ "@radix-ui/react-slot" "^1.0.2"
+ "@radix-ui/react-use-callback-ref" "^1.0.1"
+ "@radix-ui/react-use-controllable-state" "^1.0.1"
+ "@radix-ui/react-use-layout-effect" "1.0.1"
+ "@radix-ui/react-use-previous" "^1.0.1"
+ "@radix-ui/react-visually-hidden" "^1.0.3"
+ aria-hidden "^1.2.4"
+ react-remove-scroll "^2.5.9"
+
+"@strapi/utils@4.25.1":
+ version "4.25.1"
+ resolved "https://registry.yarnpkg.com/@strapi/utils/-/utils-4.25.1.tgz#9df2726bae6a75b0de9a104166f0a84af51e0de1"
+ integrity sha512-QuvGfAbHU2I1ebZThoF3GzAtLQVClP9VKrL3IaSy3MfKbH9xzLpg+ROiwUAawgR7Qi/zF8865VCCe4tdqJUB7Q==
+ dependencies:
+ "@sindresorhus/slugify" "1.1.0"
+ date-fns "2.30.0"
+ http-errors "1.8.1"
+ lodash "4.17.21"
+ p-map "4.0.0"
+ yup "0.32.9"
+
+"@swc/core-darwin-arm64@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.6.3.tgz#63e7d9b3259ffc305075a0bb1c771428723e3df5"
+ integrity sha512-3r7cJf1BcE30iyF1rnOSKrEzIR+cqnyYSZvivrm62TZdXVsIjfXe1xulsKGxZgNeLY5erIu7ukvMvBvPhnQvqA==
+
+"@swc/core-darwin-x64@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.6.3.tgz#ec405e5af8a3fe65e03f3b47a527d4945e2cb1e5"
+ integrity sha512-8GLZ23IgVpF5xh2SbS5ZW/12/EEBuRU1hFOLB5rKERJU0y1RJ6YhDMf/FuOWhfHQcFM7TeedBwHIzaF+tdKKlw==
+
+"@swc/core-linux-arm-gnueabihf@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.6.3.tgz#30d83a296b1160afac91b27c0837b4f29fdb86fb"
+ integrity sha512-VQ/bduX7WhLOlGbJLMG7UH0LBehjjx43R4yuk55rjjJLqpvX5fQzMsWhQdIZ5vsc+4ORzdgtEAlpumTv6bsD1A==
+
+"@swc/core-linux-arm64-gnu@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.6.3.tgz#7c988c2dd7ea12f4c4a0c52f32474d6dc8b0cf36"
+ integrity sha512-jHIQ/PCwtdDBIF/BiC5DochswuCAIW/T5skJ+eDMbta7+QtEnZCXTZWpT5ORoEY/gtsE2fjpOA4TS6fBBvXqUw==
+
+"@swc/core-linux-arm64-musl@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.6.3.tgz#4ca5662622494eb1da5752de3e57dde8901d858d"
+ integrity sha512-gA6velEUD27Dwu0BlR9hCcFzkWq2YL2pDAU5qbgeuGhaMiUCBssfqTQB+2ctEnV+AZx+hSMJOHvtA+uFZjfRrw==
+
+"@swc/core-linux-x64-gnu@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.6.3.tgz#55c79e321b473239d27073b4e3f3ef7e3d93a8d3"
+ integrity sha512-fy4qoBDr5I8r+ZNCZxs/oZcmu4j/8mtSud6Ka102DaSxEjNg0vfIdo9ITsVIPsofhUTmDKjQsPB2O7YUlJAioQ==
+
+"@swc/core-linux-x64-musl@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.6.3.tgz#ad5c1b7857ac7753eb50ba1fa61fcf35143bab68"
+ integrity sha512-c/twcMbq/Gpq47G+b3kWgoaCujpXO11aRgJx6am+CprvP4uNeBHEpQkxD+DQmdWFHisZd0i9GB8NG3e7L9Rz9Q==
+
+"@swc/core-win32-arm64-msvc@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.6.3.tgz#58708feba33a104c13543c3681760670001fa97a"
+ integrity sha512-y6RxMtX45acReQmzkxcEfJscfBXce6QjuNgWQHHs9exA592BZzmolDUwgmAyjyvopz1lWX+KdymdZFKvuDSx4w==
+
+"@swc/core-win32-ia32-msvc@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.6.3.tgz#1f2faac0b9e20888749a850b39a3541801c3c9a5"
+ integrity sha512-41h7z3xgukl1HDDwhquaeOPSP1OWeHl+mWKnJVmmwd3ui/oowUDCO856qa6JagBgPSnAGfyXwv6vthuXwyCcWA==
+
+"@swc/core-win32-x64-msvc@1.6.3":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.6.3.tgz#19b8999fd7d0b82960ea81edbdb9130a6154cfb0"
+ integrity sha512-//bnwo9b8Vp1ED06eXCHyGZ5xIpdkQgg2fuFDdtd1FITl7r5bdQh2ryRzPiKiGwgXZwZQitUshI4JeEX9IuW+Q==
+
+"@swc/core@^1.3.96":
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.6.3.tgz#4ca4563a8eae7c34640ad1aa24251b95a68a81be"
+ integrity sha512-mZpei+LqE+AL+nwgERMQey9EJA9/yhHTN6nwbobH5GnSij/lhfTdGfAb1iumOrroqEcXbHUaK//7wOw7DjBGdA==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+ "@swc/types" "^0.1.8"
+ optionalDependencies:
+ "@swc/core-darwin-arm64" "1.6.3"
+ "@swc/core-darwin-x64" "1.6.3"
+ "@swc/core-linux-arm-gnueabihf" "1.6.3"
+ "@swc/core-linux-arm64-gnu" "1.6.3"
+ "@swc/core-linux-arm64-musl" "1.6.3"
+ "@swc/core-linux-x64-gnu" "1.6.3"
+ "@swc/core-linux-x64-musl" "1.6.3"
+ "@swc/core-win32-arm64-msvc" "1.6.3"
+ "@swc/core-win32-ia32-msvc" "1.6.3"
+ "@swc/core-win32-x64-msvc" "1.6.3"
+
+"@swc/counter@^0.1.3":
+ version "0.1.3"
+ resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
+ integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
+
+"@swc/helpers@^0.5.0":
+ version "0.5.11"
+ resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.11.tgz#5bab8c660a6e23c13b2d23fcd1ee44a2db1b0cb7"
+ integrity sha512-YNlnKRWF2sVojTpIyzwou9XoTNbzbzONwRhOoniEioF1AtaitTvVZblaQRrAzChWQ1bLYyYSWzM18y4WwgzJ+A==
+ dependencies:
+ tslib "^2.4.0"
+
+"@swc/types@^0.1.8":
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.8.tgz#2c81d107c86cfbd0c3a05ecf7bb54c50dfa58a95"
+ integrity sha512-RNFA3+7OJFNYY78x0FYwi1Ow+iF1eF5WvmfY1nXPOEH4R2p/D4Cr1vzje7dNAI2aLFqpv8Wyz4oKSWqIZArpQA==
+ dependencies:
+ "@swc/counter" "^0.1.3"
+
+"@szmarczak/http-timer@^4.0.5":
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-4.0.6.tgz#b4a914bb62e7c272d4e5989fe4440f812ab1d807"
+ integrity sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==
+ dependencies:
+ defer-to-connect "^2.0.0"
+
+"@types/argparse@1.0.38":
+ version "1.0.38"
+ resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9"
+ integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==
+
+"@types/body-parser@*":
+ version "1.19.5"
+ resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.5.tgz#04ce9a3b677dc8bd681a17da1ab9835dc9d3ede4"
+ integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==
+ dependencies:
+ "@types/connect" "*"
+ "@types/node" "*"
+
+"@types/cacheable-request@^6.0.1":
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183"
+ integrity sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==
+ dependencies:
+ "@types/http-cache-semantics" "*"
+ "@types/keyv" "^3.1.4"
+ "@types/node" "*"
+ "@types/responselike" "^1.0.0"
+
+"@types/connect@*":
+ version "3.4.38"
+ resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858"
+ integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==
+ dependencies:
+ "@types/node" "*"
+
+"@types/eslint-scope@^3.7.3":
+ version "3.7.7"
+ resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5"
+ integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==
+ dependencies:
+ "@types/eslint" "*"
+ "@types/estree" "*"
+
+"@types/eslint@*":
+ version "8.56.10"
+ resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.10.tgz#eb2370a73bf04a901eeba8f22595c7ee0f7eb58d"
+ integrity sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
+"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0", "@types/estree@^1.0.5":
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+ integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
+
+"@types/express-serve-static-core@^4.17.33":
+ version "4.19.5"
+ resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz#218064e321126fcf9048d1ca25dd2465da55d9c6"
+ integrity sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+ "@types/send" "*"
+
+"@types/express@^4.17.17":
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d"
+ integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^4.17.33"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
+
+"@types/fined@*":
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/@types/fined/-/fined-1.1.5.tgz#504b87a0de8813e06e7d226f34c1cefb70d9afb0"
+ integrity sha512-2N93vadEGDFhASTIRbizbl4bNqpMOId5zZfj6hHqYZfEzEfO9onnU4Im8xvzo8uudySDveDHBOOSlTWf38ErfQ==
+
+"@types/formidable@^1.0.31":
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/@types/formidable/-/formidable-1.2.8.tgz#78a95c12606920aeb1165ab2670943d726a79325"
+ integrity sha512-6psvrUy5VDYb+yaPJReF1WrRsz+FBwyJutK9Twz1Efa27tm07bARNIkK2B8ZPWq80dXqpKfrxTO96xrtPp+AuA==
+ dependencies:
+ "@types/node" "*"
+
+"@types/glob@^7.1.1":
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
+ integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
+ dependencies:
+ "@types/minimatch" "*"
+ "@types/node" "*"
+
+"@types/hoist-non-react-statics@^3.3.1":
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494"
+ integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==
+ dependencies:
+ "@types/react" "*"
+ hoist-non-react-statics "^3.3.0"
+
+"@types/html-minifier-terser@^6.0.0":
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#4fc33a00c1d0c16987b1a20cf92d20614c55ac35"
+ integrity sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg==
+
+"@types/http-cache-semantics@*":
+ version "4.0.4"
+ resolved "https://registry.yarnpkg.com/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz#b979ebad3919799c979b17c72621c0bc0a31c6c4"
+ integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==
+
+"@types/http-errors@*":
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
+ integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==
+
+"@types/inquirer@^6.5.0":
+ version "6.5.0"
+ resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-6.5.0.tgz#b83b0bf30b88b8be7246d40e51d32fe9d10e09be"
+ integrity sha512-rjaYQ9b9y/VFGOpqBEXRavc3jh0a+e6evAbI31tMda8VlPaSy0AZJfXsvmIe3wklc7W6C3zCSfleuMXR7NOyXw==
+ dependencies:
+ "@types/through" "*"
+ rxjs "^6.4.0"
+
+"@types/interpret@*":
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/@types/interpret/-/interpret-1.1.3.tgz#fa7695584530077e0338948188bb59270077ab7a"
+ integrity sha512-uBaBhj/BhilG58r64mtDb/BEdH51HIQLgP5bmWzc5qCtFMja8dCk/IOJmk36j0lbi9QHwI6sbtUNGuqXdKCAtQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/is-hotkey@^0.1.1":
+ version "0.1.10"
+ resolved "https://registry.yarnpkg.com/@types/is-hotkey/-/is-hotkey-0.1.10.tgz#cf440fab9bf75ffba4e1a16e8df28938de0778c9"
+ integrity sha512-RvC8KMw5BCac1NvRRyaHgMMEtBaZ6wh0pyPTBu7izn4Sj/AX9Y4aXU5c7rX8PnM/knsuUpC1IeoBkANtxBypsQ==
+
+"@types/json-schema@*", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
+ version "7.0.15"
+ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
+ integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+
+"@types/jsonwebtoken@^9.0.2":
+ version "9.0.6"
+ resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz#d1af3544d99ad992fb6681bbe60676e06b032bd3"
+ integrity sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==
+ dependencies:
+ "@types/node" "*"
+
+"@types/keyv@^3.1.4":
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/@types/keyv/-/keyv-3.1.4.tgz#3ccdb1c6751b0c7e52300bcdacd5bcbf8faa75b6"
+ integrity sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==
+ dependencies:
+ "@types/node" "*"
+
+"@types/liftoff@^2.5.1":
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/@types/liftoff/-/liftoff-2.5.1.tgz#2eb4c1f86e9d5ee85571e56db0084b26af129ced"
+ integrity sha512-nB3R6Q9CZcM07JgiTK6ibxqrG1reiHE+UX7em/W1DKwVBxDlfKWOefQjk4jubY5xX+GDxVsWR2KD1SenPby8ow==
+ dependencies:
+ "@types/fined" "*"
+ "@types/interpret" "*"
+ "@types/node" "*"
+
+"@types/lodash@^4.14.149", "@types/lodash@^4.14.165":
+ version "4.17.5"
+ resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.5.tgz#e6c29b58e66995d57cd170ce3e2a61926d55ee04"
+ integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==
+
+"@types/mime@^1":
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
+ integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
+
+"@types/minimatch@*":
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca"
+ integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==
+
+"@types/node@*":
+ version "20.14.7"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.7.tgz#342cada27f97509eb8eb2dbc003edf21ce8ab5a8"
+ integrity sha512-uTr2m2IbJJucF3KUxgnGOZvYbN0QgkGyWxG6973HCpMYFy2KfcgYuIwkJQMQkt1VbBMlvWRbpshFTLxnxCZjKQ==
+ dependencies:
+ undici-types "~5.26.4"
+
+"@types/node@18.15.13":
+ version "18.15.13"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469"
+ integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==
+
+"@types/normalize-package-data@^2.4.0":
+ version "2.4.4"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901"
+ integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==
+
+"@types/parse-json@^4.0.0":
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.2.tgz#5950e50960793055845e956c427fc2b0d70c5239"
+ integrity sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==
+
+"@types/prop-types@*":
+ version "15.7.12"
+ resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.12.tgz#12bb1e2be27293c1406acb6af1c3f3a1481d98c6"
+ integrity sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==
+
+"@types/qs@*":
+ version "6.9.15"
+ resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.15.tgz#adde8a060ec9c305a82de1babc1056e73bd64dce"
+ integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==
+
+"@types/range-parser@*":
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
+ integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
+
+"@types/react-transition-group@^4.4.0":
+ version "4.4.10"
+ resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac"
+ integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==
+ dependencies:
+ "@types/react" "*"
+
+"@types/react@*", "@types/react@16 || 17 || 18":
+ version "18.3.3"
+ resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.3.tgz#9679020895318b0915d7a3ab004d92d33375c45f"
+ integrity sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==
+ dependencies:
+ "@types/prop-types" "*"
+ csstype "^3.0.2"
+
+"@types/responselike@^1.0.0":
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/@types/responselike/-/responselike-1.0.3.tgz#cc29706f0a397cfe6df89debfe4bf5cea159db50"
+ integrity sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==
+ dependencies:
+ "@types/node" "*"
+
+"@types/send@*":
+ version "0.17.4"
+ resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.4.tgz#6619cd24e7270793702e4e6a4b958a9010cfc57a"
+ integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==
+ dependencies:
+ "@types/mime" "^1"
+ "@types/node" "*"
+
+"@types/serve-static@*":
+ version "1.15.7"
+ resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714"
+ integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==
+ dependencies:
+ "@types/http-errors" "*"
+ "@types/node" "*"
+ "@types/send" "*"
+
+"@types/through@*":
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.33.tgz#14ebf599320e1c7851e7d598149af183c6b9ea56"
+ integrity sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==
+ dependencies:
+ "@types/node" "*"
+
+"@types/triple-beam@^1.3.2":
+ version "1.3.5"
+ resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c"
+ integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==
+
+"@types/use-sync-external-store@^0.0.3":
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
+ integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
+
+"@ucast/core@^1.0.0", "@ucast/core@^1.4.1", "@ucast/core@^1.6.1":
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/@ucast/core/-/core-1.10.2.tgz#30b6b893479823265368e528b61b042f752f2c92"
+ integrity sha512-ons5CwXZ/51wrUPfoduC+cO7AS1/wRb0ybpQJ9RrssossDxVy4t49QxWoWgfBDvVKsz9VXzBk9z0wqTdZ+Cq8g==
+
+"@ucast/js@^3.0.0":
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/@ucast/js/-/js-3.0.4.tgz#c57ec2182505c9ad63a5b08ff5911f89ac605262"
+ integrity sha512-TgG1aIaCMdcaEyckOZKQozn1hazE0w90SVdlpIJ/er8xVumE11gYAtSbw/LBeUnA4fFnFWTcw3t6reqseeH/4Q==
+ dependencies:
+ "@ucast/core" "^1.0.0"
+
+"@ucast/mongo2js@^1.3.0":
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/@ucast/mongo2js/-/mongo2js-1.3.4.tgz#579f9e5eb074cba54640d5c70c71c500580f3af3"
+ integrity sha512-ahazOr1HtelA5AC1KZ9x0UwPMqqimvfmtSm/PRRSeKKeE5G2SCqTgwiNzO7i9jS8zA3dzXpKVPpXMkcYLnyItA==
+ dependencies:
+ "@ucast/core" "^1.6.1"
+ "@ucast/js" "^3.0.0"
+ "@ucast/mongo" "^2.4.0"
+
+"@ucast/mongo@^2.4.0":
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/@ucast/mongo/-/mongo-2.4.3.tgz#92b1dd7c0ab06a907f2ab1422aa3027518ccc05e"
+ integrity sha512-XcI8LclrHWP83H+7H2anGCEeDq0n+12FU2mXCTz6/Tva9/9ddK/iacvvhCyW6cijAAOILmt0tWplRyRhVyZLsA==
+ dependencies:
+ "@ucast/core" "^1.4.1"
+
+"@uiw/codemirror-extensions-basic-setup@4.22.2":
+ version "4.22.2"
+ resolved "https://registry.yarnpkg.com/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.22.2.tgz#a114dc9ebad6de41a441c8aca655d9c34934a7d9"
+ integrity sha512-zcHGkldLFN3cGoI5XdOGAkeW24yaAgrDEYoyPyWHODmPiNwybQQoZGnH3qUdzZwUaXtAcLWoAeOPzfNRW2yGww==
+ dependencies:
+ "@codemirror/autocomplete" "^6.0.0"
+ "@codemirror/commands" "^6.0.0"
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/lint" "^6.0.0"
+ "@codemirror/search" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+
+"@uiw/react-codemirror@^4.21.25":
+ version "4.22.2"
+ resolved "https://registry.yarnpkg.com/@uiw/react-codemirror/-/react-codemirror-4.22.2.tgz#18dcb79e31cf34e0704366f3041da93ff3c64109"
+ integrity sha512-okCSl+WJG63gRx8Fdz7v0C6RakBQnbb3pHhuzIgDB+fwhipgFodSnu2n9oOsQesJ5YQ7mSOcKMgX0JEsu4nnfQ==
+ dependencies:
+ "@babel/runtime" "^7.18.6"
+ "@codemirror/commands" "^6.1.0"
+ "@codemirror/state" "^6.1.1"
+ "@codemirror/theme-one-dark" "^6.0.0"
+ "@uiw/codemirror-extensions-basic-setup" "4.22.2"
+ codemirror "^6.0.0"
+
+"@vitejs/plugin-react-swc@3.5.0":
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.5.0.tgz#1fadff5148003e8091168c431e44c850f9a39e74"
+ integrity sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig==
+ dependencies:
+ "@swc/core" "^1.3.96"
+
+"@vitest/expect@1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@vitest/expect/-/expect-1.6.0.tgz#0b3ba0914f738508464983f4d811bc122b51fb30"
+ integrity sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==
+ dependencies:
+ "@vitest/spy" "1.6.0"
+ "@vitest/utils" "1.6.0"
+ chai "^4.3.10"
+
+"@vitest/runner@1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@vitest/runner/-/runner-1.6.0.tgz#a6de49a96cb33b0e3ba0d9064a3e8d6ce2f08825"
+ integrity sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==
+ dependencies:
+ "@vitest/utils" "1.6.0"
+ p-limit "^5.0.0"
+ pathe "^1.1.1"
+
+"@vitest/snapshot@1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@vitest/snapshot/-/snapshot-1.6.0.tgz#deb7e4498a5299c1198136f56e6e0f692e6af470"
+ integrity sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==
+ dependencies:
+ magic-string "^0.30.5"
+ pathe "^1.1.1"
+ pretty-format "^29.7.0"
+
+"@vitest/spy@1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@vitest/spy/-/spy-1.6.0.tgz#362cbd42ccdb03f1613798fde99799649516906d"
+ integrity sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==
+ dependencies:
+ tinyspy "^2.2.0"
+
+"@vitest/utils@1.6.0":
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/@vitest/utils/-/utils-1.6.0.tgz#5c5675ca7d6f546a7b4337de9ae882e6c57896a1"
+ integrity sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==
+ dependencies:
+ diff-sequences "^29.6.3"
+ estree-walker "^3.0.3"
+ loupe "^2.3.7"
+ pretty-format "^29.7.0"
+
+"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb"
+ integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg==
+ dependencies:
+ "@webassemblyjs/helper-numbers" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+
+"@webassemblyjs/floating-point-hex-parser@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431"
+ integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==
+
+"@webassemblyjs/helper-api-error@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768"
+ integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==
+
+"@webassemblyjs/helper-buffer@1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6"
+ integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw==
+
+"@webassemblyjs/helper-numbers@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5"
+ integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==
+ dependencies:
+ "@webassemblyjs/floating-point-hex-parser" "1.11.6"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9"
+ integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==
+
+"@webassemblyjs/helper-wasm-section@1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf"
+ integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g==
+ dependencies:
+ "@webassemblyjs/ast" "1.12.1"
+ "@webassemblyjs/helper-buffer" "1.12.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/wasm-gen" "1.12.1"
+
+"@webassemblyjs/ieee754@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a"
+ integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7"
+ integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.11.6":
+ version "1.11.6"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a"
+ integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==
+
+"@webassemblyjs/wasm-edit@^1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b"
+ integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g==
+ dependencies:
+ "@webassemblyjs/ast" "1.12.1"
+ "@webassemblyjs/helper-buffer" "1.12.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/helper-wasm-section" "1.12.1"
+ "@webassemblyjs/wasm-gen" "1.12.1"
+ "@webassemblyjs/wasm-opt" "1.12.1"
+ "@webassemblyjs/wasm-parser" "1.12.1"
+ "@webassemblyjs/wast-printer" "1.12.1"
+
+"@webassemblyjs/wasm-gen@1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547"
+ integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w==
+ dependencies:
+ "@webassemblyjs/ast" "1.12.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wasm-opt@1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5"
+ integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg==
+ dependencies:
+ "@webassemblyjs/ast" "1.12.1"
+ "@webassemblyjs/helper-buffer" "1.12.1"
+ "@webassemblyjs/wasm-gen" "1.12.1"
+ "@webassemblyjs/wasm-parser" "1.12.1"
+
+"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937"
+ integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ==
+ dependencies:
+ "@webassemblyjs/ast" "1.12.1"
+ "@webassemblyjs/helper-api-error" "1.11.6"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.6"
+ "@webassemblyjs/ieee754" "1.11.6"
+ "@webassemblyjs/leb128" "1.11.6"
+ "@webassemblyjs/utf8" "1.11.6"
+
+"@webassemblyjs/wast-printer@1.12.1":
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac"
+ integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==
+ dependencies:
+ "@webassemblyjs/ast" "1.12.1"
+ "@xtuc/long" "4.2.2"
+
+"@xtuc/ieee754@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+ integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+ integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+"@zxing/text-encoding@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@zxing/text-encoding/-/text-encoding-0.9.0.tgz#fb50ffabc6c7c66a0c96b4c03e3d9be74864b70b"
+ integrity sha512-U/4aVJ2mxI0aDNI8Uq0wEhMgY+u4CNtEb0om3+y3+niDAsoTCOB33UF0sxpzqzdqXLqmvc+vZyAt4O8pPdfkwA==
+
+abitype@1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/abitype/-/abitype-1.0.4.tgz#a817ff44860e8a84e9a37ed22aa9b738dbb51dba"
+ integrity sha512-UivtYZOGJGE8rsrM/N5vdRkUpqEZVmuTumfTuolm7m/6O09wprd958rx8kUBwVAAAhQDveGAgD0GJdBuR8s6tw==
+
+accepts@^1.3.5:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
+ integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==
+ dependencies:
+ mime-types "~2.1.34"
+ negotiator "0.6.3"
+
+acorn-import-attributes@^1.9.5:
+ version "1.9.5"
+ resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef"
+ integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==
+
+acorn-walk@^8.0.0, acorn-walk@^8.3.2:
+ version "8.3.3"
+ resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.3.tgz#9caeac29eefaa0c41e3d4c65137de4d6f34df43e"
+ integrity sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==
+ dependencies:
+ acorn "^8.11.0"
+
+acorn@^8.0.4, acorn@^8.11.0, acorn@^8.11.3, acorn@^8.7.1, acorn@^8.8.2:
+ version "8.12.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.0.tgz#1627bfa2e058148036133b8d9b51a700663c294c"
+ integrity sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==
+
+addressparser@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/addressparser/-/addressparser-1.0.1.tgz#47afbe1a2a9262191db6838e4fd1d39b40821746"
+ integrity sha512-aQX7AISOMM7HFE0iZ3+YnD07oIeJqWGVnJ+ZIKaBZAk03ftmVYVqsGas/rbXKR21n4D/hKCSHypvcyOkds/xzg==
+
+aes-js@4.0.0-beta.5:
+ version "4.0.0-beta.5"
+ resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-4.0.0-beta.5.tgz#8d2452c52adedebc3a3e28465d858c11ca315873"
+ integrity sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==
+
+agent-base@6:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77"
+ integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==
+ dependencies:
+ debug "4"
+
+aggregate-error@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a"
+ integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==
+ dependencies:
+ clean-stack "^2.0.0"
+ indent-string "^4.0.0"
+
+ajv-draft-04@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8"
+ integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==
+
+ajv-formats@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520"
+ integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==
+ dependencies:
+ ajv "^8.0.0"
+
+ajv-formats@~3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578"
+ integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==
+ dependencies:
+ ajv "^8.0.0"
+
+ajv-keywords@^3.5.2:
+ version "3.5.2"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
+ integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
+
+ajv-keywords@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16"
+ integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+
+ajv@^6.12.5:
+ version "6.12.6"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
+ integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
+ 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"
+
+ajv@^8.0.0, ajv@^8.9.0:
+ version "8.16.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.16.0.tgz#22e2a92b94f005f7e0f9c9d39652ef0b8f6f0cb4"
+ integrity sha512-F0twR8U1ZU67JIEtekUcLkXkoO5mMMmgGD8sK/xUFzJ805jxHQl92hImFAqqXMyMYjSPOyUPAwHYhB72g5sTXw==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.4.1"
+
+ajv@~8.13.0:
+ version "8.13.0"
+ resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.13.0.tgz#a3939eaec9fb80d217ddf0c3376948c023f28c91"
+ integrity sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==
+ dependencies:
+ fast-deep-equal "^3.1.3"
+ json-schema-traverse "^1.0.0"
+ require-from-string "^2.0.2"
+ uri-js "^4.4.1"
+
+ansi-align@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59"
+ integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==
+ dependencies:
+ string-width "^4.1.0"
+
+ansi-escapes@^4.2.1:
+ version "4.3.2"
+ resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e"
+ integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==
+ dependencies:
+ type-fest "^0.21.3"
+
+ansi-html-community@0.0.8, ansi-html-community@^0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/ansi-html-community/-/ansi-html-community-0.0.8.tgz#69fbc4d6ccbe383f9736934ae34c3f8290f1bf41"
+ integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==
+
+ansi-regex@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+ integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==
+
+ansi-regex@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
+ integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
+
+ansi-regex@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+ integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
+
+ansi-regex@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a"
+ integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==
+
+ansi-styles@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+ integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==
+
+ansi-styles@^3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+ integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+ dependencies:
+ color-convert "^1.9.0"
+
+ansi-styles@^4.0.0, ansi-styles@^4.1.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+ integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
+ dependencies:
+ color-convert "^2.0.1"
+
+ansi-styles@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b"
+ integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==
+
+ansi-styles@^6.1.0:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5"
+ integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==
+
+any-promise@^1.0.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f"
+ integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==
+
+anymatch@~3.1.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e"
+ integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
+argparse@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
+ integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==
+
+argparse@~1.0.9:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+ integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+ dependencies:
+ sprintf-js "~1.0.2"
+
+aria-hidden@^1.1.1, aria-hidden@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.4.tgz#b78e383fdbc04d05762c78b4a25a501e736c4522"
+ integrity sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==
+ dependencies:
+ tslib "^2.0.0"
+
+arr-diff@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+ integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==
+
+arr-union@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+ integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==
+
+array-each@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f"
+ integrity sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==
+
+array-slice@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
+ integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==
+
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
+array-unique@^0.3.2:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+ integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ==
+
+asn1.js@^5.0.0, asn1.js@^5.3.0:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07"
+ integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==
+ dependencies:
+ bn.js "^4.0.0"
+ inherits "^2.0.1"
+ minimalistic-assert "^1.0.0"
+ safer-buffer "^2.1.0"
+
+assertion-error@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
+ integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
+
+assign-symbols@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+ integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==
+
+async@^3.2.3, async@^3.2.4:
+ version "3.2.5"
+ resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66"
+ integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==
+
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
+atob@^2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+ integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+available-typed-arrays@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846"
+ integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==
+ dependencies:
+ possible-typed-array-names "^1.0.0"
+
+aws-sdk@^2.1528.0:
+ version "2.1646.0"
+ resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1646.0.tgz#5616e367135d8b930cf850c2dc386dff8df984af"
+ integrity sha512-PAvDiR8ow3zjO0T5HMda04kXIzQ5e1zeWxWGSUodRwu9W569gZPBnqzcPX3PJFNAKBZnZBdbNgsci1g2nXCcBg==
+ dependencies:
+ buffer "4.9.2"
+ events "1.1.1"
+ ieee754 "1.1.13"
+ jmespath "0.16.0"
+ querystring "0.2.0"
+ sax "1.2.1"
+ url "0.10.3"
+ util "^0.12.4"
+ uuid "8.0.0"
+ xml2js "0.6.2"
+
+axios@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.0.tgz#f1e5292f26b2fd5c2e66876adc5b06cdbd7d2102"
+ integrity sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==
+ dependencies:
+ follow-redirects "^1.15.0"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
+axios@^1.4.0, axios@^1.5.1:
+ version "1.7.2"
+ resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.2.tgz#b625db8a7051fbea61c35a3cbb3a1daa7b9c7621"
+ integrity sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==
+ dependencies:
+ follow-redirects "^1.15.6"
+ form-data "^4.0.0"
+ proxy-from-env "^1.1.0"
+
+b4a@^1.6.4:
+ version "1.6.6"
+ resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.6.tgz#a4cc349a3851987c3c4ac2d7785c18744f6da9ba"
+ integrity sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==
+
+babel-plugin-macros@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
+ integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ cosmiconfig "^7.0.0"
+ resolve "^1.19.0"
+
+"babel-plugin-styled-components@>= 1.12.0":
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/babel-plugin-styled-components/-/babel-plugin-styled-components-2.1.4.tgz#9a1f37c7f32ef927b4b008b529feb4a2c82b1092"
+ integrity sha512-Xgp9g+A/cG47sUyRwwYxGM4bR/jDRg5N6it/8+HxCnbT5XNKSKDT9xm4oag/osgqjC2It/vH0yXsomOG6k558g==
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.22.5"
+ "@babel/helper-module-imports" "^7.22.5"
+ "@babel/plugin-syntax-jsx" "^7.22.5"
+ lodash "^4.17.21"
+ picomatch "^2.3.1"
+
+balanced-match@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
+ integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+
+bare-events@^2.0.0, bare-events@^2.2.0:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.4.2.tgz#3140cca7a0e11d49b3edc5041ab560659fd8e1f8"
+ integrity sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==
+
+bare-fs@^2.1.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/bare-fs/-/bare-fs-2.3.1.tgz#cdbd63dac7a552dfb2b87d18c822298d1efd213d"
+ integrity sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==
+ dependencies:
+ bare-events "^2.0.0"
+ bare-path "^2.0.0"
+ bare-stream "^2.0.0"
+
+bare-os@^2.1.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/bare-os/-/bare-os-2.4.0.tgz#5de5e3ba7704f459c9656629edca7cc736e06608"
+ integrity sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==
+
+bare-path@^2.0.0, bare-path@^2.1.0:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/bare-path/-/bare-path-2.1.3.tgz#594104c829ef660e43b5589ec8daef7df6cedb3e"
+ integrity sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==
+ dependencies:
+ bare-os "^2.1.0"
+
+bare-stream@^2.0.0:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/bare-stream/-/bare-stream-2.1.3.tgz#070b69919963a437cc9e20554ede079ce0a129b2"
+ integrity sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==
+ dependencies:
+ streamx "^2.18.0"
+
+base64-js@^1.0.2, base64-js@^1.3.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
+ integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
+
+base@^0.11.1:
+ version "0.11.2"
+ resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+ integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+ dependencies:
+ cache-base "^1.0.1"
+ class-utils "^0.3.5"
+ component-emitter "^1.2.1"
+ define-property "^1.0.0"
+ isobject "^3.0.1"
+ mixin-deep "^1.2.0"
+ pascalcase "^0.1.1"
+
+bcryptjs@2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
+ integrity sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==
+
+big-integer@^1.6.16, big-integer@^1.6.44:
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
+
+big.js@^5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+ integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
+binary-extensions@^2.0.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522"
+ integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==
+
+bl@^4.0.3, bl@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a"
+ integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==
+ dependencies:
+ buffer "^5.5.0"
+ inherits "^2.0.4"
+ readable-stream "^3.4.0"
+
+block-stream2@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/block-stream2/-/block-stream2-2.1.0.tgz#ac0c5ef4298b3857796e05be8ebed72196fa054b"
+ integrity sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==
+ dependencies:
+ readable-stream "^3.4.0"
+
+bn.js@^4.0.0, bn.js@^4.11.9:
+ version "4.12.0"
+ resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88"
+ integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==
+
+boolbase@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+ integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
+
+boxen@5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50"
+ integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==
+ dependencies:
+ ansi-align "^3.0.0"
+ camelcase "^6.2.0"
+ chalk "^4.1.0"
+ cli-boxes "^2.2.1"
+ string-width "^4.2.2"
+ type-fest "^0.20.2"
+ widest-line "^3.1.0"
+ wrap-ansi "^7.0.0"
+
+bplist-parser@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e"
+ integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==
+ dependencies:
+ big-integer "^1.6.44"
+
+brace-expansion@^1.1.7:
+ version "1.1.11"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+ integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+ dependencies:
+ balanced-match "^1.0.0"
+ concat-map "0.0.1"
+
+brace-expansion@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
+ integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
+ dependencies:
+ balanced-match "^1.0.0"
+
+braces@^2.3.1, braces@^3.0.3, braces@~3.0.2:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789"
+ integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==
+ dependencies:
+ fill-range "^7.1.1"
+
+broadcast-channel@^3.4.1:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937"
+ integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==
+ dependencies:
+ "@babel/runtime" "^7.7.2"
+ detect-node "^2.1.0"
+ js-sha3 "0.8.0"
+ microseconds "0.2.0"
+ nano-time "1.0.0"
+ oblivious-set "1.0.0"
+ rimraf "3.0.2"
+ unload "2.2.0"
+
+brorand@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+ integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==
+
+browser-or-node@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/browser-or-node/-/browser-or-node-2.1.1.tgz#738790b3a86a8fc020193fa581273fbe65eaea0f"
+ integrity sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg==
+
+browserslist-to-esbuild@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/browserslist-to-esbuild/-/browserslist-to-esbuild-1.2.0.tgz#5c5b9ca73106da02e0168007396c4ec4c1e6d643"
+ integrity sha512-ftrrbI/VHBgEnmnSyhkqvQVMp6jAKybfs0qMIlm7SLBrQTGMsdCIP4q3BoKeLsZTBQllIQtY9kbxgRYV2WU47g==
+ dependencies:
+ browserslist "^4.17.3"
+
+browserslist@^4.17.3, browserslist@^4.21.10, browserslist@^4.22.2:
+ version "4.23.1"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.1.tgz#ce4af0534b3d37db5c1a4ca98b9080f985041e96"
+ integrity sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==
+ dependencies:
+ caniuse-lite "^1.0.30001629"
+ electron-to-chromium "^1.4.796"
+ node-releases "^2.0.14"
+ update-browserslist-db "^1.0.16"
+
+buffer-crc32@^0.2.13:
+ version "0.2.13"
+ resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
+ integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==
+
+buffer-equal-constant-time@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
+ integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
+
+buffer-from@^1.0.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
+ integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
+
+buffer@4.9.2:
+ version "4.9.2"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8"
+ integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==
+ dependencies:
+ base64-js "^1.0.2"
+ ieee754 "^1.1.4"
+ isarray "^1.0.0"
+
+buffer@^5.1.0, buffer@^5.5.0:
+ version "5.7.1"
+ resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0"
+ integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==
+ dependencies:
+ base64-js "^1.3.1"
+ ieee754 "^1.1.13"
+
+buildmail@3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/buildmail/-/buildmail-3.10.0.tgz#c6826d716e7945bb6f6b1434b53985e029a03159"
+ integrity sha512-6e5sDN/pl3en5Klqdfyir7LEIBiFr9oqZuvYaEyVwjxpIbBZN+98e0j87Fz2Ukl8ud32rbk9VGOZAnsOZ7pkaA==
+ dependencies:
+ addressparser "1.0.1"
+ libbase64 "0.1.0"
+ libmime "2.1.0"
+ libqp "1.1.0"
+ nodemailer-fetch "1.6.0"
+ nodemailer-shared "1.1.0"
+
+bundle-name@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a"
+ integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==
+ dependencies:
+ run-applescript "^5.0.0"
+
+byte-size@7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3"
+ integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A==
+
+bytes@3.1.2, bytes@^3.0.0:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
+ integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==
+
+cac@^6.7.14:
+ version "6.7.14"
+ resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959"
+ integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==
+
+cache-base@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+ integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+ dependencies:
+ collection-visit "^1.0.0"
+ component-emitter "^1.2.1"
+ get-value "^2.0.6"
+ has-value "^1.0.0"
+ isobject "^3.0.1"
+ set-value "^2.0.0"
+ to-object-path "^0.3.0"
+ union-value "^1.0.0"
+ unset-value "^1.0.0"
+
+cache-content-type@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/cache-content-type/-/cache-content-type-1.0.1.tgz#035cde2b08ee2129f4a8315ea8f00a00dba1453c"
+ integrity sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==
+ dependencies:
+ mime-types "^2.1.18"
+ ylru "^1.2.0"
+
+cacheable-lookup@^5.0.3:
+ version "5.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005"
+ integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==
+
+cacheable-request@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.4.tgz#7a33ebf08613178b403635be7b899d3e69bbe817"
+ integrity sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==
+ dependencies:
+ clone-response "^1.0.2"
+ get-stream "^5.1.0"
+ http-cache-semantics "^4.0.0"
+ keyv "^4.0.0"
+ lowercase-keys "^2.0.0"
+ normalize-url "^6.0.1"
+ responselike "^2.0.0"
+
+call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
+ integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ set-function-length "^1.2.1"
+
+callsites@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+ integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camel-case@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+ integrity sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case "^1.1.1"
+
+camel-case@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
+ integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
+ dependencies:
+ pascal-case "^3.1.2"
+ tslib "^2.0.3"
+
+camelcase@^6.2.0:
+ version "6.3.0"
+ resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
+ integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
+
+camelize@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/camelize/-/camelize-1.0.1.tgz#89b7e16884056331a35d6b5ad064332c91daa6c3"
+ integrity sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==
+
+caniuse-lite@^1.0.30001629:
+ version "1.0.30001636"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz#b15f52d2bdb95fad32c2f53c0b68032b85188a78"
+ integrity sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==
+
+chai@^4.3.10:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1"
+ integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==
+ dependencies:
+ assertion-error "^1.1.0"
+ check-error "^1.0.3"
+ deep-eql "^4.1.3"
+ get-func-name "^2.0.2"
+ loupe "^2.3.6"
+ pathval "^1.1.1"
+ type-detect "^4.0.8"
+
+chalk@4.1.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
+chalk@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+ integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==
+ dependencies:
+ ansi-styles "^2.2.1"
+ escape-string-regexp "^1.0.2"
+ has-ansi "^2.0.0"
+ strip-ansi "^3.0.0"
+ supports-color "^2.0.0"
+
+chalk@^2.0.1, chalk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+ integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+ dependencies:
+ ansi-styles "^3.2.1"
+ escape-string-regexp "^1.0.5"
+ supports-color "^5.3.0"
+
+change-case@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.1.0.tgz#0e611b7edc9952df2e8513b27b42de72647dd17e"
+ integrity sha512-2AZp7uJZbYEzRPsFoa+ijKdvp9zsrnnt6+yFokfwEpeJm0xuJDVoxiRCAaTzyJND8GJkofo2IcKWaUZ/OECVzw==
+ dependencies:
+ camel-case "^3.0.0"
+ constant-case "^2.0.0"
+ dot-case "^2.1.0"
+ header-case "^1.0.0"
+ is-lower-case "^1.1.0"
+ is-upper-case "^1.1.0"
+ lower-case "^1.1.1"
+ lower-case-first "^1.0.0"
+ no-case "^2.3.2"
+ param-case "^2.1.0"
+ pascal-case "^2.0.0"
+ path-case "^2.1.0"
+ sentence-case "^2.1.0"
+ snake-case "^2.1.0"
+ swap-case "^1.1.0"
+ title-case "^2.1.0"
+ upper-case "^1.1.1"
+ upper-case-first "^1.1.0"
+
+chardet@^0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+ integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+check-error@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694"
+ integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==
+ dependencies:
+ get-func-name "^2.0.2"
+
+chokidar@3.5.3:
+ version "3.5.3"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
+ integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+chokidar@^3.5.2, chokidar@^3.5.3:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
+ integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
+ dependencies:
+ anymatch "~3.1.2"
+ braces "~3.0.2"
+ glob-parent "~5.1.2"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.6.0"
+ optionalDependencies:
+ fsevents "~2.3.2"
+
+chownr@^1.1.1:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b"
+ integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==
+
+chownr@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece"
+ integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==
+
+chownr@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/chownr/-/chownr-3.0.0.tgz#9855e64ecd240a9cc4267ce8a4aa5d24a1da15e4"
+ integrity sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==
+
+chrome-trace-event@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b"
+ integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==
+
+ci-info@3.8.0:
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91"
+ integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==
+
+class-utils@^0.3.5:
+ version "0.3.6"
+ resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+ integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+ dependencies:
+ arr-union "^3.1.0"
+ define-property "^0.2.5"
+ isobject "^3.0.0"
+ static-extend "^0.1.1"
+
+clean-css@^5.2.2:
+ version "5.3.3"
+ resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.3.tgz#b330653cd3bd6b75009cc25c714cae7b93351ccd"
+ integrity sha512-D5J+kHaVb/wKSFcyyV75uCn8fiY4sV38XJoe4CUyGQ+mOU/fMVYUdH1hJC+CJQ5uY3EnW27SbJYS4X8BiLrAFg==
+ dependencies:
+ source-map "~0.6.0"
+
+clean-stack@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
+ integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
+
+cli-boxes@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f"
+ integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==
+
+cli-cursor@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+ integrity sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==
+ dependencies:
+ restore-cursor "^2.0.0"
+
+cli-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307"
+ integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==
+ dependencies:
+ restore-cursor "^3.1.0"
+
+cli-progress@3.12.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942"
+ integrity sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==
+ dependencies:
+ string-width "^4.2.3"
+
+cli-spinners@^2.0.0, cli-spinners@^2.5.0:
+ version "2.9.2"
+ resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41"
+ integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==
+
+cli-table3@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.2.tgz#aaf5df9d8b5bf12634dc8b3040806a0c07120d2a"
+ integrity sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw==
+ dependencies:
+ string-width "^4.2.0"
+ optionalDependencies:
+ "@colors/colors" "1.5.0"
+
+cli-width@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6"
+ integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==
+
+cliui@^7.0.2:
+ version "7.0.4"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f"
+ integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.0"
+ wrap-ansi "^7.0.0"
+
+cliui@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
+ integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==
+ dependencies:
+ string-width "^4.2.0"
+ strip-ansi "^6.0.1"
+ wrap-ansi "^7.0.0"
+
+clone-response@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.3.tgz#af2032aa47816399cf5f0a1d0db902f517abb8c3"
+ integrity sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==
+ dependencies:
+ mimic-response "^1.0.0"
+
+clone@^1.0.2:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
+ integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==
+
+co-body@^5.1.1:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/co-body/-/co-body-5.2.0.tgz#5a0a658c46029131e0e3a306f67647302f71c124"
+ integrity sha512-sX/LQ7LqUhgyaxzbe7IqwPeTr2yfpfUIQ/dgpKo6ZI4y4lpQA0YxAomWIY+7I7rHWcG02PG+OuPREzMW/5tszQ==
+ dependencies:
+ inflation "^2.0.0"
+ qs "^6.4.0"
+ raw-body "^2.2.0"
+ type-is "^1.6.14"
+
+co-body@^6.0.0:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/co-body/-/co-body-6.2.0.tgz#afd776d60e5659f4eee862df83499698eb1aea1b"
+ integrity sha512-Kbpv2Yd1NdL1V/V4cwLVxraHDV6K8ayohr2rmH0J87Er8+zJjcTa6dAn9QMPC9CRgU8+aNajKbSf1TzDB1yKPA==
+ dependencies:
+ "@hapi/bourne" "^3.0.0"
+ inflation "^2.0.0"
+ qs "^6.5.2"
+ raw-body "^2.3.3"
+ type-is "^1.6.16"
+
+co@^4.6.0:
+ version "4.6.0"
+ resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
+ integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==
+
+"codemirror5@npm:codemirror@^5.65.11":
+ version "5.65.16"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.65.16.tgz#efc0661be6bf4988a6a1c2fe6893294638cdb334"
+ integrity sha512-br21LjYmSlVL0vFCPWPfhzUCT34FM/pAdK7rRIZwa0rrtrIdotvP4Oh4GUHsu2E3IrQMCfRkL/fN3ytMNxVQvg==
+
+codemirror@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-6.0.1.tgz#62b91142d45904547ee3e0e0e4c1a79158035a29"
+ integrity sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==
+ dependencies:
+ "@codemirror/autocomplete" "^6.0.0"
+ "@codemirror/commands" "^6.0.0"
+ "@codemirror/language" "^6.0.0"
+ "@codemirror/lint" "^6.0.0"
+ "@codemirror/search" "^6.0.0"
+ "@codemirror/state" "^6.0.0"
+ "@codemirror/view" "^6.0.0"
+
+collection-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+ integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw==
+ dependencies:
+ map-visit "^1.0.0"
+ object-visit "^1.0.0"
+
+color-convert@^1.9.0, color-convert@^1.9.3:
+ version "1.9.3"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+ integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+ dependencies:
+ color-name "1.1.3"
+
+color-convert@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+ integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
+ dependencies:
+ color-name "~1.1.4"
+
+color-name@1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+ integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
+
+color-name@^1.0.0, color-name@~1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+ integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+color-string@^1.6.0, color-string@^1.9.0:
+ version "1.9.1"
+ resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
+ integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
+ dependencies:
+ color-name "^1.0.0"
+ simple-swizzle "^0.2.2"
+
+color@^3.1.3:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/color/-/color-3.2.1.tgz#3544dc198caf4490c3ecc9a790b54fe9ff45e164"
+ integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==
+ dependencies:
+ color-convert "^1.9.3"
+ color-string "^1.6.0"
+
+color@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
+ integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
+ dependencies:
+ color-convert "^2.0.1"
+ color-string "^1.9.0"
+
+colorette@2.0.19:
+ version "2.0.19"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
+ integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
+
+colorette@^2.0.10:
+ version "2.0.20"
+ resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a"
+ integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==
+
+colorspace@1.1.x:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/colorspace/-/colorspace-1.1.4.tgz#8d442d1186152f60453bf8070cd66eb364e59243"
+ integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==
+ dependencies:
+ color "^3.1.3"
+ text-hex "1.0.x"
+
+combined-stream@^1.0.8:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
+commander@8.3.0, commander@^8.3.0:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
+ integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
+
+commander@^10.0.0:
+ version "10.0.1"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06"
+ integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==
+
+commander@^2.20.0:
+ version "2.20.3"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
+ integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
+
+commander@^7.2.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
+ integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
+
+common-path-prefix@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/common-path-prefix/-/common-path-prefix-3.0.0.tgz#7d007a7e07c58c4b4d5f433131a19141b29f11e0"
+ integrity sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==
+
+component-emitter@^1.2.1:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17"
+ integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ==
+
+compressible@^2.0.0:
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba"
+ integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==
+ dependencies:
+ mime-db ">= 1.43.0 < 2"
+
+compute-scroll-into-view@^1.0.20:
+ version "1.0.20"
+ resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.20.tgz#1768b5522d1172754f5d0c9b02de3af6be506a43"
+ integrity sha512-UCB0ioiyj8CRjtrvaceBLqqhZCVP+1B8+NWQhmdsm0VXOJtobBCf1dBQmebCCo34qZmUwZfIH2MZLqNHazrfjg==
+
+compute-scroll-into-view@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz#753f11d972596558d8fe7c6bcbc8497690ab4c87"
+ integrity sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg==
+
+concat-map@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+ integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
+
+concurrently@8.2.2:
+ version "8.2.2"
+ resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-8.2.2.tgz#353141985c198cfa5e4a3ef90082c336b5851784"
+ integrity sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==
+ dependencies:
+ chalk "^4.1.2"
+ date-fns "^2.30.0"
+ lodash "^4.17.21"
+ rxjs "^7.8.1"
+ shell-quote "^1.8.1"
+ spawn-command "0.0.2"
+ supports-color "^8.1.1"
+ tree-kill "^1.2.2"
+ yargs "^17.7.2"
+
+confbox@^0.1.7:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.7.tgz#ccfc0a2bcae36a84838e83a3b7f770fb17d6c579"
+ integrity sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==
+
+config-chain@^1.1.11:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4"
+ integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==
+ dependencies:
+ ini "^1.3.4"
+ proto-list "~1.2.1"
+
+configstore@5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
+ integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
+ dependencies:
+ dot-prop "^5.2.0"
+ graceful-fs "^4.1.2"
+ make-dir "^3.0.0"
+ unique-string "^2.0.0"
+ write-file-atomic "^3.0.0"
+ xdg-basedir "^4.0.0"
+
+constant-case@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46"
+ integrity sha512-eS0N9WwmjTqrOmR3o83F5vW8Z+9R1HnVz3xmzT2PMFug9ly+Au/fxRWlEBSb6LcZwspSsEn9Xs1uw9YgzAg1EQ==
+ dependencies:
+ snake-case "^2.1.0"
+ upper-case "^1.1.1"
+
+content-disposition@~0.5.2:
+ version "0.5.4"
+ resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe"
+ integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==
+ dependencies:
+ safe-buffer "5.2.1"
+
+content-type@^1.0.4:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
+ integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
+
+convert-source-map@^1.5.0:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f"
+ integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
+
+cookie-signature@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.1.tgz#790dea2cce64638c7ae04d9fabed193bd7ccf3b4"
+ integrity sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw==
+
+cookie@^0.4.1:
+ version "0.4.2"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
+ integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
+
+cookie@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b"
+ integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
+
+cookies@~0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.8.0.tgz#1293ce4b391740a8406e3c9870e828c4b54f3f90"
+ integrity sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==
+ dependencies:
+ depd "~2.0.0"
+ keygrip "~1.1.0"
+
+copy-descriptor@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+ integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==
+
+copy-to@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/copy-to/-/copy-to-2.0.1.tgz#2680fbb8068a48d08656b6098092bdafc906f4a5"
+ integrity sha512-3DdaFaU/Zf1AnpLiFDeNCD4TOWe3Zl2RZaTzUvWiIk5ERzcCodOE20Vqq4fzCbNoHURFHT4/us/Lfq+S2zyY4w==
+
+copyfiles@2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/copyfiles/-/copyfiles-2.4.1.tgz#d2dcff60aaad1015f09d0b66e7f0f1c5cd3c5da5"
+ integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==
+ dependencies:
+ glob "^7.0.5"
+ minimatch "^3.0.3"
+ mkdirp "^1.0.4"
+ noms "0.0.0"
+ through2 "^2.0.1"
+ untildify "^4.0.0"
+ yargs "^16.1.0"
+
+core-js-pure@^3.23.3, core-js-pure@^3.30.2:
+ version "3.37.1"
+ resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.37.1.tgz#2b4b34281f54db06c9a9a5bd60105046900553bd"
+ integrity sha512-J/r5JTHSmzTxbiYYrzXg9w1VpqrYt+gexenBE9pugeyhwPZTAEJddyiReJWsLO6uNQ8xJZFbod6XC7KKwatCiA==
+
+core-util-is@^1.0.2, core-util-is@~1.0.0:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
+ integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
+
+cosmiconfig@^7.0.0:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
+ integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ import-fresh "^3.2.1"
+ parse-json "^5.0.0"
+ path-type "^4.0.0"
+ yaml "^1.10.0"
+
+cosmiconfig@^8.2.0:
+ version "8.3.6"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3"
+ integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==
+ dependencies:
+ import-fresh "^3.3.0"
+ js-yaml "^4.1.0"
+ parse-json "^5.2.0"
+ path-type "^4.0.0"
+
+crc@^3.8.0:
+ version "3.8.0"
+ resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
+ integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
+ dependencies:
+ buffer "^5.1.0"
+
+crelt@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
+ integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
+
+cron-parser@^3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/cron-parser/-/cron-parser-3.5.0.tgz#b1a9da9514c0310aa7ef99c2f3f1d0f8c235257c"
+ integrity sha512-wyVZtbRs6qDfFd8ap457w3XVntdvqcwBGxBoTvJQH9KGVKL/fB+h2k3C8AqiVxvUQKN1Ps/Ns46CNViOpVDhfQ==
+ dependencies:
+ is-nan "^1.3.2"
+ luxon "^1.26.0"
+
+cropperjs@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/cropperjs/-/cropperjs-1.6.0.tgz#de9f23b7e397a53fd0dc10cc0d6fe31fe1e2019a"
+ integrity sha512-BzLU/ecrfsbflwxgu+o7sQTrTlo52pVRZkTVrugEK5uyj6n8qKwAHP4s6+DWHqlXLqQ5B9+cM2MKeXiNfAsF6Q==
+
+cross-env@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
+ integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
+ dependencies:
+ cross-spawn "^7.0.1"
+
+cross-fetch@^3.1.5:
+ version "3.1.8"
+ resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82"
+ integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==
+ dependencies:
+ node-fetch "^2.6.12"
+
+cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3:
+ version "7.0.3"
+ resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
+ integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
+ dependencies:
+ path-key "^3.1.0"
+ shebang-command "^2.0.0"
+ which "^2.0.1"
+
+crypto-random-string@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
+ integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
+
+css-color-keywords@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05"
+ integrity sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==
+
+css-loader@^6.9.0:
+ version "6.11.0"
+ resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.11.0.tgz#33bae3bf6363d0a7c2cf9031c96c744ff54d85ba"
+ integrity sha512-CTJ+AEQJjq5NzLga5pE39qdiSV56F8ywCIsqNIRF0r7BDgWsN25aazToqAFg7ZrtA/U016xudB3ffgweORxX7g==
+ dependencies:
+ icss-utils "^5.1.0"
+ postcss "^8.4.33"
+ postcss-modules-extract-imports "^3.1.0"
+ postcss-modules-local-by-default "^4.0.5"
+ postcss-modules-scope "^3.2.0"
+ postcss-modules-values "^4.0.0"
+ postcss-value-parser "^4.2.0"
+ semver "^7.5.4"
+
+css-select@^4.1.3:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
+ integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
+ dependencies:
+ boolbase "^1.0.0"
+ css-what "^6.0.1"
+ domhandler "^4.3.1"
+ domutils "^2.8.0"
+ nth-check "^2.0.1"
+
+css-to-react-native@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.2.0.tgz#cdd8099f71024e149e4f6fe17a7d46ecd55f1e32"
+ integrity sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==
+ dependencies:
+ camelize "^1.0.0"
+ css-color-keywords "^1.0.0"
+ postcss-value-parser "^4.0.2"
+
+css-what@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
+ integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
+
+cssesc@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+ integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+csstype@^3.0.2:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+ integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+date-fns-tz@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-2.0.0.tgz#1b14c386cb8bc16fc56fe333d4fc34ae1d1099d5"
+ integrity sha512-OAtcLdB9vxSXTWHdT8b398ARImVwQMyjfYGkKD2zaGpHseG2UPHbHjXELReErZFxWdSLph3c2zOaaTyHfOhERQ==
+
+date-fns@2.30.0, date-fns@^2.30.0:
+ version "2.30.0"
+ resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0"
+ integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==
+ dependencies:
+ "@babel/runtime" "^7.21.0"
+
+dayjs@^1.11.10:
+ version "1.11.11"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.11.tgz#dfe0e9d54c5f8b68ccf8ca5f72ac603e7e5ed59e"
+ integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg==
+
+debounce@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5"
+ integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==
+
+debug@4, debug@^4, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4:
+ version "4.3.5"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e"
+ integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==
+ dependencies:
+ ms "2.1.2"
+
+debug@4.3.4:
+ version "4.3.4"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
+ integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
+ dependencies:
+ ms "2.1.2"
+
+debug@^2.2.0, debug@^2.3.3:
+ version "2.6.9"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+ integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+ dependencies:
+ ms "2.0.0"
+
+debug@^3.1.0:
+ version "3.2.7"
+ resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
+ integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
+ dependencies:
+ ms "^2.1.1"
+
+decode-uri-component@^0.2.0, decode-uri-component@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9"
+ integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==
+
+decompress-response@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc"
+ integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==
+ dependencies:
+ mimic-response "^3.1.0"
+
+decompress-response@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-7.0.0.tgz#dc42107cc29a258aa8983fddc81c92351810f6fb"
+ integrity sha512-6IvPrADQyyPGLpMnUh6kfKiqy7SrbXbjoUuZ90WMBJKErzv2pCiwlGEXjRX9/54OnTq+XFVnkOnOMzclLI5aEA==
+ dependencies:
+ mimic-response "^3.1.0"
+
+deep-eql@^4.1.3:
+ version "4.1.4"
+ resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.4.tgz#d0d3912865911bb8fac5afb4e3acfa6a28dc72b7"
+ integrity sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==
+ dependencies:
+ type-detect "^4.0.0"
+
+deep-equal@~1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
+ integrity sha512-bHtC0iYvWhyaTzvV3CZgPeZQqCOBGyGsVV7v4eevpdkLHfiSrXUdBG+qAuSz4RI70sszvjQ1QSZ98An1yNwpSw==
+
+deep-extend@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+ integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+deepmerge@^2.1.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-2.2.1.tgz#5d3ff22a01c00f645405a2fbc17d0778a1801170"
+ integrity sha512-R9hc1Xa/NOBi9WRVUWg19rl1UB7Tt4kuPd+thNJgFZoxXsTz7ncaPaeIm+40oSGuP33DfMb4sZt1QIGiJzC4EA==
+
+deepmerge@^4.2.2:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a"
+ integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==
+
+default-browser-id@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c"
+ integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==
+ dependencies:
+ bplist-parser "^0.2.0"
+ untildify "^4.0.0"
+
+default-browser@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da"
+ integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==
+ dependencies:
+ bundle-name "^3.0.0"
+ default-browser-id "^3.0.0"
+ execa "^7.1.1"
+ titleize "^3.0.0"
+
+defaults@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a"
+ integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==
+ dependencies:
+ clone "^1.0.2"
+
+defer-to-connect@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
+ integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
+
+define-data-property@^1.0.1, define-data-property@^1.1.4:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
+ integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
+ dependencies:
+ es-define-property "^1.0.0"
+ es-errors "^1.3.0"
+ gopd "^1.0.1"
+
+define-lazy-prop@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
+ integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
+
+define-lazy-prop@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f"
+ integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==
+
+define-properties@^1.1.3:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c"
+ integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==
+ dependencies:
+ define-data-property "^1.0.1"
+ has-property-descriptors "^1.0.0"
+ object-keys "^1.1.1"
+
+define-property@^0.2.5:
+ version "0.2.5"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+ integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA==
+ dependencies:
+ is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+ integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA==
+ dependencies:
+ is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+ integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+ dependencies:
+ is-descriptor "^1.0.2"
+ isobject "^3.0.1"
+
+del@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7"
+ integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA==
+ dependencies:
+ globby "^10.0.1"
+ graceful-fs "^4.2.2"
+ is-glob "^4.0.1"
+ is-path-cwd "^2.2.0"
+ is-path-inside "^3.0.1"
+ p-map "^3.0.0"
+ rimraf "^3.0.0"
+ slash "^3.0.0"
+
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
+delegates@1.0.0, delegates@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+ integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==
+
+depd@2.0.0, depd@^2.0.0, depd@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
+ integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
+
+depd@~1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+ integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==
+
+destroy@^1.0.4:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
+ integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
+
+detect-file@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+ integrity sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==
+
+detect-indent@^6.0.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6"
+ integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==
+
+detect-indent@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-7.0.1.tgz#cbb060a12842b9c4d333f1cac4aa4da1bb66bc25"
+ integrity sha512-Mc7QhQ8s+cLrnUfU/Ji94vG/r8M26m8f++vyres4ZoojaRDpZ1eSIh/EpzLNwlWuvzSZ3UbDFspjFvTDXe6e/g==
+
+detect-libc@^2.0.0, detect-libc@^2.0.2:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700"
+ integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
+
+detect-newline@^4.0.0:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-4.0.1.tgz#fcefdb5713e1fb8cb2839b8b6ee22e6716ab8f23"
+ integrity sha512-qE3Veg1YXzGHQhlA6jzebZN2qVf6NX+A7m7qlhCGG30dJixrAQhYOsJjsnBjJkCSmuOPpCk30145fr8FV0bzog==
+
+detect-node-es@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
+ integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
+
+detect-node@^2.0.4, detect-node@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
+ integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
+
+diff-sequences@^29.6.3:
+ version "29.6.3"
+ resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
+ integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
+
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
+direction@^1.0.3:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/direction/-/direction-1.0.4.tgz#2b86fb686967e987088caf8b89059370d4837442"
+ integrity sha512-GYqKi1aH7PJXxdhTeZBFrg8vUBeKXi+cNprXsC1kpJcbcVnV9wBsrOu1cQEdG0WeQwlfHiy3XvnKfIrJ2R0NzQ==
+
+dkim-signer@0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/dkim-signer/-/dkim-signer-0.2.2.tgz#aa81ec071eeed3622781baa922044d7800e5f308"
+ integrity sha512-24OZ3cCA30UTRz+Plpg+ibfPq3h7tDtsJRg75Bo0pGakZePXcPBddY80bKi1Bi7Jsz7tL5Cw527mhCRDvNFgfg==
+ dependencies:
+ libmime "^2.0.3"
+
+dnd-core@^16.0.1:
+ version "16.0.1"
+ resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-16.0.1.tgz#a1c213ed08961f6bd1959a28bb76f1a868360d19"
+ integrity sha512-HK294sl7tbw6F6IeuK16YSBUoorvHpY8RHO+9yFfaJyCDVb6n7PRcezrOEOa2SBCqiYpemh5Jx20ZcjKdFAVng==
+ dependencies:
+ "@react-dnd/asap" "^5.0.1"
+ "@react-dnd/invariant" "^4.0.1"
+ redux "^4.2.0"
+
+dom-converter@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
+ integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==
+ dependencies:
+ utila "~0.4"
+
+dom-helpers@^5.0.1:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
+ integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
+ dependencies:
+ "@babel/runtime" "^7.8.7"
+ csstype "^3.0.2"
+
+dom-serializer@^1.0.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
+ integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.2.0"
+ entities "^2.0.0"
+
+dom-serializer@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-2.0.0.tgz#e41b802e1eedf9f6cae183ce5e622d789d7d8e53"
+ integrity sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.2"
+ entities "^4.2.0"
+
+domelementtype@^2.0.1, domelementtype@^2.2.0, domelementtype@^2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
+ integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
+
+domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
+ integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
+ dependencies:
+ domelementtype "^2.2.0"
+
+domhandler@^5.0.2, domhandler@^5.0.3:
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-5.0.3.tgz#cc385f7f751f1d1fc650c21374804254538c7d31"
+ integrity sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==
+ dependencies:
+ domelementtype "^2.3.0"
+
+domutils@^2.5.2, domutils@^2.8.0:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
+ integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
+ dependencies:
+ dom-serializer "^1.0.1"
+ domelementtype "^2.2.0"
+ domhandler "^4.2.0"
+
+domutils@^3.0.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/domutils/-/domutils-3.1.0.tgz#c47f551278d3dc4b0b1ab8cbb42d751a6f0d824e"
+ integrity sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==
+ dependencies:
+ dom-serializer "^2.0.0"
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+
+dot-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-2.1.1.tgz#34dcf37f50a8e93c2b3bca8bb7fb9155c7da3bee"
+ integrity sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==
+ dependencies:
+ no-case "^2.2.0"
+
+dot-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
+ integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
+dot-prop@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88"
+ integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
+ dependencies:
+ is-obj "^2.0.0"
+
+dotenv@14.2.0:
+ version "14.2.0"
+ resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-14.2.0.tgz#7e77fd5dd6cff5942c4496e1acf2d0f37a9e67aa"
+ integrity sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw==
+
+duplexer@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
+ integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
+
+eastasianwidth@^0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb"
+ integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==
+
+ecdsa-sig-formatter@1.0.11:
+ version "1.0.11"
+ resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf"
+ integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+ee-first@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+ integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==
+
+electron-to-chromium@^1.4.796:
+ version "1.4.808"
+ resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.808.tgz#85b2f93a5e32c2949a1a4d39375851945c936835"
+ integrity sha512-0ItWyhPYnww2VOuCGF4s1LTfbrdAV2ajy/TN+ZTuhR23AHI6rWHCrBXJ/uxoXOvRRqw8qjYVrG81HFI7x/2wdQ==
+
+elliptic@^6.5.4:
+ version "6.5.5"
+ resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.5.tgz#c715e09f78b6923977610d4c2346d6ce22e6dded"
+ integrity sha512-7EjbcmUm17NQFu4Pmgmq2olYMj8nwMnpcddByChSUjArp8F5DQWcIcpriwO4ZToLNAJig0yiyjswfyGNje/ixw==
+ dependencies:
+ bn.js "^4.11.9"
+ brorand "^1.1.0"
+ hash.js "^1.0.0"
+ hmac-drbg "^1.0.1"
+ inherits "^2.0.4"
+ minimalistic-assert "^1.0.1"
+ minimalistic-crypto-utils "^1.0.1"
+
+emittery@^0.12.1:
+ version "0.12.1"
+ resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.12.1.tgz#cb9a4a18745816f7a1fa03a8953e7eaededb45f2"
+ integrity sha512-pYyW59MIZo0HxPFf+Vb3+gacUu0gxVS3TZwB2ClwkEZywgF9f9OJDoVmNLojTn0vKX3tO9LC+pdQEcLP4Oz/bQ==
+
+emoji-regex@^8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
+ integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
+
+emoji-regex@^9.2.2:
+ version "9.2.2"
+ resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72"
+ integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
+
+emojis-list@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
+ integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
+
+enabled@2.0.x:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2"
+ integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==
+
+encodeurl@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+ integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
+
+end-of-stream@^1.1.0, end-of-stream@^1.4.1:
+ version "1.4.4"
+ resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
+ integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
+ dependencies:
+ once "^1.4.0"
+
+enhanced-resolve@^5.17.0:
+ version "5.17.0"
+ resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz#d037603789dd9555b89aaec7eb78845c49089bc5"
+ integrity sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA==
+ dependencies:
+ graceful-fs "^4.2.4"
+ tapable "^2.2.0"
+
+entities@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
+ integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
+
+entities@^4.2.0, entities@^4.4.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48"
+ integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==
+
+entities@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/entities/-/entities-2.1.0.tgz#992d3129cf7df6870b96c57858c249a120f8b8b5"
+ integrity sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==
+
+error-ex@^1.3.1:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+ integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+ dependencies:
+ is-arrayish "^0.2.1"
+
+error-stack-parser@^2.0.6:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286"
+ integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==
+ dependencies:
+ stackframe "^1.3.4"
+
+es-define-property@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
+ integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
+ dependencies:
+ get-intrinsic "^1.2.4"
+
+es-errors@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
+ integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
+
+es-module-lexer@^1.2.1:
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.5.3.tgz#25969419de9c0b1fbe54279789023e8a9a788412"
+ integrity sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==
+
+esbuild-loader@^2.21.0:
+ version "2.21.0"
+ resolved "https://registry.yarnpkg.com/esbuild-loader/-/esbuild-loader-2.21.0.tgz#2698a3e565b0db2bb19a3dd91c2b6c9aad526c80"
+ integrity sha512-k7ijTkCT43YBSZ6+fBCW1Gin7s46RrJ0VQaM8qA7lq7W+OLsGgtLyFV8470FzYi/4TeDexniTBTPTwZUnXXR5g==
+ dependencies:
+ esbuild "^0.16.17"
+ joycon "^3.0.1"
+ json5 "^2.2.0"
+ loader-utils "^2.0.0"
+ tapable "^2.2.0"
+ webpack-sources "^1.4.3"
+
+esbuild-register@3.5.0:
+ version "3.5.0"
+ resolved "https://registry.yarnpkg.com/esbuild-register/-/esbuild-register-3.5.0.tgz#449613fb29ab94325c722f560f800dd946dc8ea8"
+ integrity sha512-+4G/XmakeBAsvJuDugJvtyF1x+XJT4FMocynNpxrvEBViirpfUn2PgNpCHedfWhF4WokNsO/OvMKrmJOIJsI5A==
+ dependencies:
+ debug "^4.3.4"
+
+esbuild@0.19.11:
+ version "0.19.11"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.11.tgz#4a02dca031e768b5556606e1b468fe72e3325d96"
+ integrity sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==
+ optionalDependencies:
+ "@esbuild/aix-ppc64" "0.19.11"
+ "@esbuild/android-arm" "0.19.11"
+ "@esbuild/android-arm64" "0.19.11"
+ "@esbuild/android-x64" "0.19.11"
+ "@esbuild/darwin-arm64" "0.19.11"
+ "@esbuild/darwin-x64" "0.19.11"
+ "@esbuild/freebsd-arm64" "0.19.11"
+ "@esbuild/freebsd-x64" "0.19.11"
+ "@esbuild/linux-arm" "0.19.11"
+ "@esbuild/linux-arm64" "0.19.11"
+ "@esbuild/linux-ia32" "0.19.11"
+ "@esbuild/linux-loong64" "0.19.11"
+ "@esbuild/linux-mips64el" "0.19.11"
+ "@esbuild/linux-ppc64" "0.19.11"
+ "@esbuild/linux-riscv64" "0.19.11"
+ "@esbuild/linux-s390x" "0.19.11"
+ "@esbuild/linux-x64" "0.19.11"
+ "@esbuild/netbsd-x64" "0.19.11"
+ "@esbuild/openbsd-x64" "0.19.11"
+ "@esbuild/sunos-x64" "0.19.11"
+ "@esbuild/win32-arm64" "0.19.11"
+ "@esbuild/win32-ia32" "0.19.11"
+ "@esbuild/win32-x64" "0.19.11"
+
+esbuild@^0.16.17:
+ version "0.16.17"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.16.17.tgz#fc2c3914c57ee750635fee71b89f615f25065259"
+ integrity sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==
+ optionalDependencies:
+ "@esbuild/android-arm" "0.16.17"
+ "@esbuild/android-arm64" "0.16.17"
+ "@esbuild/android-x64" "0.16.17"
+ "@esbuild/darwin-arm64" "0.16.17"
+ "@esbuild/darwin-x64" "0.16.17"
+ "@esbuild/freebsd-arm64" "0.16.17"
+ "@esbuild/freebsd-x64" "0.16.17"
+ "@esbuild/linux-arm" "0.16.17"
+ "@esbuild/linux-arm64" "0.16.17"
+ "@esbuild/linux-ia32" "0.16.17"
+ "@esbuild/linux-loong64" "0.16.17"
+ "@esbuild/linux-mips64el" "0.16.17"
+ "@esbuild/linux-ppc64" "0.16.17"
+ "@esbuild/linux-riscv64" "0.16.17"
+ "@esbuild/linux-s390x" "0.16.17"
+ "@esbuild/linux-x64" "0.16.17"
+ "@esbuild/netbsd-x64" "0.16.17"
+ "@esbuild/openbsd-x64" "0.16.17"
+ "@esbuild/sunos-x64" "0.16.17"
+ "@esbuild/win32-arm64" "0.16.17"
+ "@esbuild/win32-ia32" "0.16.17"
+ "@esbuild/win32-x64" "0.16.17"
+
+esbuild@^0.19.3:
+ version "0.19.12"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.12.tgz#dc82ee5dc79e82f5a5c3b4323a2a641827db3e04"
+ integrity sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==
+ optionalDependencies:
+ "@esbuild/aix-ppc64" "0.19.12"
+ "@esbuild/android-arm" "0.19.12"
+ "@esbuild/android-arm64" "0.19.12"
+ "@esbuild/android-x64" "0.19.12"
+ "@esbuild/darwin-arm64" "0.19.12"
+ "@esbuild/darwin-x64" "0.19.12"
+ "@esbuild/freebsd-arm64" "0.19.12"
+ "@esbuild/freebsd-x64" "0.19.12"
+ "@esbuild/linux-arm" "0.19.12"
+ "@esbuild/linux-arm64" "0.19.12"
+ "@esbuild/linux-ia32" "0.19.12"
+ "@esbuild/linux-loong64" "0.19.12"
+ "@esbuild/linux-mips64el" "0.19.12"
+ "@esbuild/linux-ppc64" "0.19.12"
+ "@esbuild/linux-riscv64" "0.19.12"
+ "@esbuild/linux-s390x" "0.19.12"
+ "@esbuild/linux-x64" "0.19.12"
+ "@esbuild/netbsd-x64" "0.19.12"
+ "@esbuild/openbsd-x64" "0.19.12"
+ "@esbuild/sunos-x64" "0.19.12"
+ "@esbuild/win32-arm64" "0.19.12"
+ "@esbuild/win32-ia32" "0.19.12"
+ "@esbuild/win32-x64" "0.19.12"
+
+esbuild@^0.21.3:
+ version "0.21.5"
+ resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d"
+ integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==
+ optionalDependencies:
+ "@esbuild/aix-ppc64" "0.21.5"
+ "@esbuild/android-arm" "0.21.5"
+ "@esbuild/android-arm64" "0.21.5"
+ "@esbuild/android-x64" "0.21.5"
+ "@esbuild/darwin-arm64" "0.21.5"
+ "@esbuild/darwin-x64" "0.21.5"
+ "@esbuild/freebsd-arm64" "0.21.5"
+ "@esbuild/freebsd-x64" "0.21.5"
+ "@esbuild/linux-arm" "0.21.5"
+ "@esbuild/linux-arm64" "0.21.5"
+ "@esbuild/linux-ia32" "0.21.5"
+ "@esbuild/linux-loong64" "0.21.5"
+ "@esbuild/linux-mips64el" "0.21.5"
+ "@esbuild/linux-ppc64" "0.21.5"
+ "@esbuild/linux-riscv64" "0.21.5"
+ "@esbuild/linux-s390x" "0.21.5"
+ "@esbuild/linux-x64" "0.21.5"
+ "@esbuild/netbsd-x64" "0.21.5"
+ "@esbuild/openbsd-x64" "0.21.5"
+ "@esbuild/sunos-x64" "0.21.5"
+ "@esbuild/win32-arm64" "0.21.5"
+ "@esbuild/win32-ia32" "0.21.5"
+ "@esbuild/win32-x64" "0.21.5"
+
+escalade@^3.1.1, escalade@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27"
+ integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==
+
+escape-html@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+ integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
+
+escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+ integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
+
+escape-string-regexp@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344"
+ integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==
+
+escape-string-regexp@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
+ integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
+
+eslint-scope@5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
+ integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
+ dependencies:
+ esrecurse "^4.3.0"
+ estraverse "^4.1.1"
+
+esm@^3.2.25:
+ version "3.2.25"
+ resolved "https://registry.yarnpkg.com/esm/-/esm-3.2.25.tgz#342c18c29d56157688ba5ce31f8431fbb795cc10"
+ integrity sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==
+
+esrecurse@^4.3.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
+ integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
+ dependencies:
+ estraverse "^5.2.0"
+
+estraverse@^4.1.1:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
+ integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
+
+estraverse@^5.2.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
+ integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
+
+estree-walker@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d"
+ integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==
+ dependencies:
+ "@types/estree" "^1.0.0"
+
+ethers@^6.13.1:
+ version "6.13.1"
+ resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.1.tgz#2b9f9c7455cde9d38b30fe6589972eb083652961"
+ integrity sha512-hdJ2HOxg/xx97Lm9HdCWk949BfYqYWpyw4//78SiwOLgASyfrNszfMUNB2joKjvGUdwhHfaiMMFFwacVVoLR9A==
+ dependencies:
+ "@adraffy/ens-normalize" "1.10.1"
+ "@noble/curves" "1.2.0"
+ "@noble/hashes" "1.3.2"
+ "@types/node" "18.15.13"
+ aes-js "4.0.0-beta.5"
+ tslib "2.4.0"
+ ws "8.17.1"
+
+events@1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924"
+ integrity sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==
+
+events@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
+ integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
+
+eventsource@2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-2.0.2.tgz#76dfcc02930fb2ff339520b6d290da573a9e8508"
+ integrity sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==
+
+execa@5.1.1, execa@^5.0.0:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd"
+ integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.0"
+ human-signals "^2.1.0"
+ is-stream "^2.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^4.0.1"
+ onetime "^5.1.2"
+ signal-exit "^3.0.3"
+ strip-final-newline "^2.0.0"
+
+execa@^7.1.1:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9"
+ integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^6.0.1"
+ human-signals "^4.3.0"
+ is-stream "^3.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^5.1.0"
+ onetime "^6.0.0"
+ signal-exit "^3.0.7"
+ strip-final-newline "^3.0.0"
+
+execa@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-8.0.1.tgz#51f6a5943b580f963c3ca9c6321796db8cc39b8c"
+ integrity sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==
+ dependencies:
+ cross-spawn "^7.0.3"
+ get-stream "^8.0.1"
+ human-signals "^5.0.0"
+ is-stream "^3.0.0"
+ merge-stream "^2.0.0"
+ npm-run-path "^5.1.0"
+ onetime "^6.0.0"
+ signal-exit "^4.1.0"
+ strip-final-newline "^3.0.0"
+
+expand-brackets@^2.1.4:
+ version "2.1.4"
+ resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+ integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==
+ dependencies:
+ debug "^2.3.3"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ posix-character-classes "^0.1.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+expand-template@^2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c"
+ integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==
+
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+ integrity sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==
+ dependencies:
+ homedir-polyfill "^1.0.1"
+
+extend-shallow@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+ integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==
+ dependencies:
+ is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+ integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==
+ dependencies:
+ assign-symbols "^1.0.0"
+ is-extendable "^1.0.1"
+
+extend@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+external-editor@^3.0.3:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+ integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+ dependencies:
+ chardet "^0.7.0"
+ iconv-lite "^0.4.24"
+ tmp "^0.0.33"
+
+extglob@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+ integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+ dependencies:
+ array-unique "^0.3.2"
+ define-property "^1.0.0"
+ expand-brackets "^2.1.4"
+ extend-shallow "^2.0.1"
+ fragment-cache "^0.2.1"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+fast-deep-equal@3.1.3, fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
+ version "3.1.3"
+ resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
+ integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
+
+fast-fifo@^1.2.0, fast-fifo@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c"
+ integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==
+
+fast-glob@^3.0.3, fast-glob@^3.3.0:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
+ integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.2"
+ merge2 "^1.3.0"
+ micromatch "^4.0.4"
+
+fast-json-stable-stringify@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
+ integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
+
+fast-safe-stringify@2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
+ integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
+
+fast-xml-parser@4.4.1, fast-xml-parser@^4.2.2:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz#86dbf3f18edf8739326447bcaac31b4ae7f6514f"
+ integrity sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==
+ dependencies:
+ strnum "^1.0.5"
+
+fastq@^1.6.0:
+ version "1.17.1"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47"
+ integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==
+ dependencies:
+ reusify "^1.0.4"
+
+fecha@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/fecha/-/fecha-4.2.3.tgz#4d9ccdbc61e8629b259fdca67e65891448d569fd"
+ integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==
+
+figures@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af"
+ integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==
+ dependencies:
+ escape-string-regexp "^1.0.5"
+
+fill-range@^7.1.1:
+ version "7.1.1"
+ resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292"
+ integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==
+ dependencies:
+ to-regex-range "^5.0.1"
+
+filter-obj@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
+ integrity sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==
+
+find-root@1.1.0, find-root@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
+ integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
+
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+ dependencies:
+ locate-path "^3.0.0"
+
+find-up@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
+ integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
+ dependencies:
+ locate-path "^5.0.0"
+ path-exists "^4.0.0"
+
+find-up@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc"
+ integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==
+ dependencies:
+ locate-path "^6.0.0"
+ path-exists "^4.0.0"
+
+findup-sync@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-2.0.0.tgz#9326b1488c22d1a6088650a86901b2d9a90a2cbc"
+ integrity sha512-vs+3unmJT45eczmcAZ6zMJtxN3l/QXeccaXQx5cu/MeJMhewVfoWZqibRkOxPnmoR59+Zy5hjabfQc6JLSah4g==
+ dependencies:
+ detect-file "^1.0.0"
+ is-glob "^3.1.0"
+ micromatch "^3.0.4"
+ resolve-dir "^1.0.1"
+
+fined@^1.0.1:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/fined/-/fined-1.2.0.tgz#d00beccf1aa2b475d16d423b0238b713a2c4a37b"
+ integrity sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==
+ dependencies:
+ expand-tilde "^2.0.2"
+ is-plain-object "^2.0.3"
+ object.defaults "^1.1.0"
+ object.pick "^1.2.0"
+ parse-filepath "^1.0.1"
+
+flagged-respawn@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41"
+ integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==
+
+fn.name@1.x.x:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/fn.name/-/fn.name-1.1.0.tgz#26cad8017967aea8731bc42961d04a3d5988accc"
+ integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
+
+follow-redirects@^1.15.0, follow-redirects@^1.15.6:
+ version "1.15.6"
+ resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
+ integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
+
+for-each@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e"
+ integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==
+ dependencies:
+ is-callable "^1.1.3"
+
+for-in@^1.0.1, for-in@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+ integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==
+
+for-own@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
+ integrity sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==
+ dependencies:
+ for-in "^1.0.1"
+
+foreground-child@^3.1.0:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.2.1.tgz#767004ccf3a5b30df39bed90718bab43fe0a59f7"
+ integrity sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==
+ dependencies:
+ cross-spawn "^7.0.0"
+ signal-exit "^4.0.1"
+
+fork-ts-checker-webpack-plugin@9.0.2:
+ version "9.0.2"
+ resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz#c12c590957837eb02b02916902dcf3e675fd2b1e"
+ integrity sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==
+ dependencies:
+ "@babel/code-frame" "^7.16.7"
+ chalk "^4.1.2"
+ chokidar "^3.5.3"
+ cosmiconfig "^8.2.0"
+ deepmerge "^4.2.2"
+ fs-extra "^10.0.0"
+ memfs "^3.4.1"
+ minimatch "^3.0.4"
+ node-abort-controller "^3.0.1"
+ schema-utils "^3.1.1"
+ semver "^7.3.5"
+ tapable "^2.2.1"
+
+form-data@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
+ integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.8"
+ mime-types "^2.1.12"
+
+formidable@^1.1.1:
+ version "1.2.6"
+ resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.6.tgz#d2a51d60162bbc9b4a055d8457a7c75315d1a168"
+ integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==
+
+formik@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/formik/-/formik-2.4.0.tgz#8243e42a89e1c9fbe9aefbd48bc8d1f10ae2950d"
+ integrity sha512-QZiWztt9fD84EYcF7Bmr431ZhIm1xUVgBACbTuJ6azPrUpVp7o6q+t9HJaIQsFZrMfcBPNBotYtDgyDpzQ3z0Q==
+ dependencies:
+ deepmerge "^2.1.1"
+ hoist-non-react-statics "^3.3.0"
+ lodash "^4.17.21"
+ lodash-es "^4.17.21"
+ react-fast-compare "^2.0.1"
+ tiny-warning "^1.0.2"
+ tslib "^1.10.0"
+
+fractional-indexing@3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/fractional-indexing/-/fractional-indexing-3.2.0.tgz#1193e63d54ff4e0cbe0c79a9ed6cfbab25d91628"
+ integrity sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ==
+
+fragment-cache@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+ integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA==
+ dependencies:
+ map-cache "^0.2.2"
+
+fresh@~0.5.2:
+ version "0.5.2"
+ resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+ integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==
+
+fs-constants@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
+ integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
+
+fs-extra@10.0.0:
+ version "10.0.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1"
+ integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-extra@^10.0.0:
+ version "10.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
+ integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-extra@^8.0.1:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
+ integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
+ dependencies:
+ graceful-fs "^4.2.0"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
+fs-extra@~7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
+ integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+ dependencies:
+ graceful-fs "^4.1.2"
+ jsonfile "^4.0.0"
+ universalify "^0.1.0"
+
+fs-jetpack@^4.3.1:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/fs-jetpack/-/fs-jetpack-4.3.1.tgz#cdfd4b64e6bfdec7c7dc55c76b39efaa7853bb20"
+ integrity sha512-dbeOK84F6BiQzk2yqqCVwCPWTxAvVGJ3fMQc6E2wuEohS28mR6yHngbrKuVCK1KHRx/ccByDylqu4H5PCP2urQ==
+ dependencies:
+ minimatch "^3.0.2"
+ rimraf "^2.6.3"
+
+fs-minipass@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb"
+ integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==
+ dependencies:
+ minipass "^3.0.0"
+
+fs-monkey@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/fs-monkey/-/fs-monkey-1.0.6.tgz#8ead082953e88d992cf3ff844faa907b26756da2"
+ integrity sha512-b1FMfwetIKymC0eioW7mTywihSQE4oLzQn1dB6rZB5fx/3NpNEdAWeCSMB+60/AeT0TCXsxzAlcYVEFCTAksWg==
+
+fs.realpath@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+ integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
+
+fsevents@*, fsevents@~2.3.2, fsevents@~2.3.3:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+ integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+function-bind@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
+ integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
+
+get-caller-file@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+ integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-func-name@^2.0.1, get-func-name@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41"
+ integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==
+
+get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
+ integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
+ dependencies:
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ has-proto "^1.0.1"
+ has-symbols "^1.0.3"
+ hasown "^2.0.0"
+
+get-it@^8.0.9:
+ version "8.6.1"
+ resolved "https://registry.yarnpkg.com/get-it/-/get-it-8.6.1.tgz#b424f136e91f7898551323378af4ad38f92c15a9"
+ integrity sha512-fCK6M+WkN1TuXzYac0RYk9OK4VdJKV1xG3fe9D3TU2is/G8ofz6/+hRBCiddO/eNPhnhMBpYIk2kNx1S4NRdsg==
+ dependencies:
+ decompress-response "^7.0.0"
+ follow-redirects "^1.15.6"
+ is-retry-allowed "^2.2.0"
+ progress-stream "^2.0.0"
+ tunnel-agent "^0.6.0"
+
+get-latest-version@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/get-latest-version/-/get-latest-version-5.1.0.tgz#928f7fda59a9a34d7c7cf3664a2006dfd9af6aa7"
+ integrity sha512-Q6IBWr/zzw57zIkJmNhI23eRTw3nZ4BWWK034meLwOYU9L3J3IpXiyM73u2pYUwN6U7ahkerCwg2T0jlxiLwsw==
+ dependencies:
+ get-it "^8.0.9"
+ registry-auth-token "^5.0.2"
+ registry-url "^5.1.0"
+ semver "^7.3.8"
+
+get-nonce@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3"
+ integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==
+
+get-package-type@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a"
+ integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
+
+get-stdin@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575"
+ integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==
+
+get-stream@^5.1.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
+ integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
+ dependencies:
+ pump "^3.0.0"
+
+get-stream@^6.0.0, get-stream@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7"
+ integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==
+
+get-stream@^8.0.1:
+ version "8.0.1"
+ resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2"
+ integrity sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==
+
+get-value@^2.0.3, get-value@^2.0.6:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+ integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA==
+
+getopts@2.3.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.3.0.tgz#71e5593284807e03e2427449d4f6712a268666f4"
+ integrity sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==
+
+git-hooks-list@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-3.1.0.tgz#386dc531dcc17474cf094743ff30987a3d3e70fc"
+ integrity sha512-LF8VeHeR7v+wAbXqfgRlTSX/1BJR9Q1vEMR8JAz1cEg6GX07+zyj3sAdDvYjj/xnlIfVuGgj4qBei1K3hKH+PA==
+
+git-up@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/git-up/-/git-up-7.0.0.tgz#bace30786e36f56ea341b6f69adfd83286337467"
+ integrity sha512-ONdIrbBCFusq1Oy0sC71F5azx8bVkvtZtMJAsv+a6lz5YAmbNnLD6HAB4gptHZVLPR8S2/kVN6Gab7lryq5+lQ==
+ dependencies:
+ is-ssh "^1.4.0"
+ parse-url "^8.1.0"
+
+git-url-parse@13.1.0:
+ version "13.1.0"
+ resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-13.1.0.tgz#07e136b5baa08d59fabdf0e33170de425adf07b4"
+ integrity sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==
+ dependencies:
+ git-up "^7.0.0"
+
+github-from-package@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
+ integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==
+
+glob-parent@^5.1.2, glob-parent@~5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
+ integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
+ dependencies:
+ is-glob "^4.0.1"
+
+glob-to-regexp@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+ integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
+glob@7.2.3, glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6:
+ version "7.2.3"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
+ integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^3.1.1"
+ once "^1.3.0"
+ path-is-absolute "^1.0.0"
+
+glob@^10.3.7:
+ version "10.4.2"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.2.tgz#bed6b95dade5c1f80b4434daced233aee76160e5"
+ integrity sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w==
+ dependencies:
+ foreground-child "^3.1.0"
+ jackspeak "^3.1.2"
+ minimatch "^9.0.4"
+ minipass "^7.1.2"
+ package-json-from-dist "^1.0.0"
+ path-scurry "^1.11.1"
+
+glob@^8.0.3:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e"
+ integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==
+ dependencies:
+ fs.realpath "^1.0.0"
+ inflight "^1.0.4"
+ inherits "2"
+ minimatch "^5.0.1"
+ once "^1.3.0"
+
+global-modules@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+ integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+ dependencies:
+ global-prefix "^1.0.1"
+ is-windows "^1.0.1"
+ resolve-dir "^1.0.0"
+
+global-prefix@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+ integrity sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==
+ dependencies:
+ expand-tilde "^2.0.2"
+ homedir-polyfill "^1.0.1"
+ ini "^1.3.4"
+ is-windows "^1.0.1"
+ which "^1.2.14"
+
+globals@^11.1.0:
+ version "11.12.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+ integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globby@^10.0.1:
+ version "10.0.2"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543"
+ integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==
+ dependencies:
+ "@types/glob" "^7.1.1"
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.0.3"
+ glob "^7.1.3"
+ ignore "^5.1.1"
+ merge2 "^1.2.3"
+ slash "^3.0.0"
+
+globby@^13.1.2:
+ version "13.2.2"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-13.2.2.tgz#63b90b1bf68619c2135475cbd4e71e66aa090592"
+ integrity sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==
+ dependencies:
+ dir-glob "^3.0.1"
+ fast-glob "^3.3.0"
+ ignore "^5.2.4"
+ merge2 "^1.4.1"
+ slash "^4.0.0"
+
+gopd@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
+ integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
+ dependencies:
+ get-intrinsic "^1.1.3"
+
+got@^11.8.2:
+ version "11.8.6"
+ resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a"
+ integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==
+ dependencies:
+ "@sindresorhus/is" "^4.0.0"
+ "@szmarczak/http-timer" "^4.0.5"
+ "@types/cacheable-request" "^6.0.1"
+ "@types/responselike" "^1.0.0"
+ cacheable-lookup "^5.0.3"
+ cacheable-request "^7.0.2"
+ decompress-response "^6.0.0"
+ http2-wrapper "^1.0.0-beta.5.2"
+ lowercase-keys "^2.0.0"
+ p-cancelable "^2.0.0"
+ responselike "^2.0.0"
+
+graceful-fs@4.2.10:
+ version "4.2.10"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
+ integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4:
+ version "4.2.11"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+ integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+grant-koa@5.4.8:
+ version "5.4.8"
+ resolved "https://registry.yarnpkg.com/grant-koa/-/grant-koa-5.4.8.tgz#2fc49ad91007588fff58559cffa44dca9f06835d"
+ integrity sha512-Kw8np9AL3Z3mZuvoSUklHJpTe3xx7iLBDauRyIwwbDLRr/5Ll6APmOFHixXj+Vw+LGEnreTxO35CyhAf9oBUMA==
+ dependencies:
+ grant "^5.4.8"
+
+grant@^5.4.8:
+ version "5.4.22"
+ resolved "https://registry.yarnpkg.com/grant/-/grant-5.4.22.tgz#b4756e7bb51a6a0091387467b4058ec6a750d69e"
+ integrity sha512-DEi+/JjXT84mmFYhSmv+SX14v+3Z7vuCIYAMwtdPCTXHMSLhWqSYqWAMXDUQZuV7yaJv2d84AYnkCFNooLKBsA==
+ dependencies:
+ qs "^6.11.2"
+ request-compose "^2.1.6"
+ request-oauth "^1.0.1"
+ optionalDependencies:
+ cookie "^0.5.0"
+ cookie-signature "^1.2.1"
+ jwk-to-pem "^2.0.5"
+ jws "^4.0.0"
+
+graphql-request@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-6.1.0.tgz#f4eb2107967af3c7a5907eb3131c671eac89be4f"
+ integrity sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==
+ dependencies:
+ "@graphql-typed-document-node/core" "^3.2.0"
+ cross-fetch "^3.1.5"
+
+graphql-tag@^2.12.6:
+ version "2.12.6"
+ resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1"
+ integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==
+ dependencies:
+ tslib "^2.1.0"
+
+graphql@^16.8.1:
+ version "16.8.2"
+ resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.8.2.tgz#54771c7ff195da913f5e70af8044a026d32eca2a"
+ integrity sha512-cvVIBILwuoSyD54U4cF/UXDh5yAobhNV/tPygI4lZhgOIJQE/WLWC4waBRb4I6bDVYb3OVx3lfHbaQOEoUD5sg==
+
+gzip-size@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
+ integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==
+ dependencies:
+ duplexer "^0.1.2"
+
+handlebars@^4.4.3:
+ version "4.7.8"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9"
+ integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==
+ dependencies:
+ minimist "^1.2.5"
+ neo-async "^2.6.2"
+ source-map "^0.6.1"
+ wordwrap "^1.0.0"
+ optionalDependencies:
+ uglify-js "^3.1.4"
+
+has-ansi@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+ integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==
+ dependencies:
+ ansi-regex "^2.0.0"
+
+has-flag@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+ integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
+
+has-flag@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+ integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
+
+has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
+ integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
+ dependencies:
+ es-define-property "^1.0.0"
+
+has-proto@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
+ integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
+
+has-symbols@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
+ integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
+
+has-tostringtag@^1.0.0, has-tostringtag@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc"
+ integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==
+ dependencies:
+ has-symbols "^1.0.3"
+
+has-value@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+ integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q==
+ dependencies:
+ get-value "^2.0.3"
+ has-values "^0.1.4"
+ isobject "^2.0.0"
+
+has-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+ integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw==
+ dependencies:
+ get-value "^2.0.6"
+ has-values "^1.0.0"
+ isobject "^3.0.0"
+
+has-values@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+ integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ==
+
+has-values@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+ integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ==
+ dependencies:
+ is-number "^3.0.0"
+ kind-of "^4.0.0"
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+ version "1.1.7"
+ resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
+ integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
+ dependencies:
+ inherits "^2.0.3"
+ minimalistic-assert "^1.0.1"
+
+hasown@^2.0.0, hasown@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
+ integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
+ dependencies:
+ function-bind "^1.1.2"
+
+he@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+ integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+header-case@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d"
+ integrity sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case "^1.1.3"
+
+helmet@^6.0.1:
+ version "6.2.0"
+ resolved "https://registry.yarnpkg.com/helmet/-/helmet-6.2.0.tgz#c29d62014be4c70b8ef092c9c5e54c8c26b8e16e"
+ integrity sha512-DWlwuXLLqbrIOltR6tFQXShj/+7Cyp0gLi6uAb8qMdFh/YBBFbKSgQ6nbXmScYd8emMctuthmgIa7tUfo9Rtyg==
+
+highlight.js@^10.4.1:
+ version "10.7.3"
+ resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
+ integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==
+
+history@^4.9.0:
+ version "4.10.1"
+ resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
+ integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ loose-envify "^1.2.0"
+ resolve-pathname "^3.0.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+ value-equal "^1.0.1"
+
+hmac-drbg@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+ integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==
+ dependencies:
+ hash.js "^1.0.3"
+ minimalistic-assert "^1.0.0"
+ minimalistic-crypto-utils "^1.0.1"
+
+hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
+ version "3.3.2"
+ resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
+ integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
+ dependencies:
+ react-is "^16.7.0"
+
+homedir-polyfill@^1.0.1:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+ integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+ dependencies:
+ parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+ version "2.8.9"
+ resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
+ integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
+
+html-entities@^2.1.0:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f"
+ integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==
+
+html-escaper@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453"
+ integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==
+
+html-minifier-terser@^6.0.2:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab"
+ integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==
+ dependencies:
+ camel-case "^4.1.2"
+ clean-css "^5.2.2"
+ commander "^8.3.0"
+ he "^1.2.0"
+ param-case "^3.0.4"
+ relateurl "^0.2.7"
+ terser "^5.10.0"
+
+html-webpack-plugin@5.6.0:
+ version "5.6.0"
+ resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz#50a8fa6709245608cb00e811eacecb8e0d7b7ea0"
+ integrity sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==
+ dependencies:
+ "@types/html-minifier-terser" "^6.0.0"
+ html-minifier-terser "^6.0.2"
+ lodash "^4.17.21"
+ pretty-error "^4.0.0"
+ tapable "^2.0.0"
+
+htmlparser2@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7"
+ integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
+ dependencies:
+ domelementtype "^2.0.1"
+ domhandler "^4.0.0"
+ domutils "^2.5.2"
+ entities "^2.0.0"
+
+htmlparser2@^8.0.0:
+ version "8.0.2"
+ resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-8.0.2.tgz#f002151705b383e62433b5cf466f5b716edaec21"
+ integrity sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==
+ dependencies:
+ domelementtype "^2.3.0"
+ domhandler "^5.0.3"
+ domutils "^3.0.1"
+ entities "^4.4.0"
+
+http-assert@^1.3.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f"
+ integrity sha512-uPpH7OKX4H25hBmU6G1jWNaqJGpTXxey+YOUizJUAgu0AjLUeC8D73hTrhvDS5D+GJN1DN1+hhc/eF/wpxtp0w==
+ dependencies:
+ deep-equal "~1.0.1"
+ http-errors "~1.8.0"
+
+http-cache-semantics@^4.0.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
+ integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
+
+http-errors@1.8.1, http-errors@^1.6.3, http-errors@^1.7.3, http-errors@^1.8.0, http-errors@~1.8.0:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
+ integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses ">= 1.5.0 < 2"
+ toidentifier "1.0.1"
+
+http-errors@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
+ integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
+ dependencies:
+ depd "2.0.0"
+ inherits "2.0.4"
+ setprototypeof "1.2.0"
+ statuses "2.0.1"
+ toidentifier "1.0.1"
+
+http-errors@~1.6.2:
+ version "1.6.3"
+ resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+ integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==
+ dependencies:
+ depd "~1.1.2"
+ inherits "2.0.3"
+ setprototypeof "1.1.0"
+ statuses ">= 1.4.0 < 2"
+
+http2-wrapper@^1.0.0-beta.5.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d"
+ integrity sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==
+ dependencies:
+ quick-lru "^5.1.1"
+ resolve-alpn "^1.0.0"
+
+https-proxy-agent@5.0.1, https-proxy-agent@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6"
+ integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==
+ dependencies:
+ agent-base "6"
+ debug "4"
+
+human-signals@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
+ integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
+
+human-signals@^4.3.0:
+ version "4.3.1"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2"
+ integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==
+
+human-signals@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-5.0.0.tgz#42665a284f9ae0dade3ba41ebc37eb4b852f3a28"
+ integrity sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==
+
+iconv-lite@0.4.13:
+ version "0.4.13"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
+ integrity sha512-QwVuTNQv7tXC5mMWFX5N5wGjmybjNBBD8P3BReTkPmipoxTUFgWM2gXNvldHQr6T14DH0Dh6qBVg98iJt7u4mQ==
+
+iconv-lite@0.4.15:
+ version "0.4.15"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb"
+ integrity sha512-RGR+c9Lm+tLsvU57FTJJtdbv2hQw42Yl2n26tVIBaYmZzLN+EGfroUugN/z9nJf9kOXd49hBmpoGr4FEm+A4pw==
+
+iconv-lite@0.4.24, iconv-lite@^0.4.24:
+ version "0.4.24"
+ resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+ integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+ dependencies:
+ safer-buffer ">= 2.1.2 < 3"
+
+icss-utils@^5.0.0, icss-utils@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
+ integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
+
+ieee754@1.1.13:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+ integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
+ieee754@^1.1.13, ieee754@^1.1.4:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
+ integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
+
+ignore-by-default@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
+ integrity sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==
+
+ignore-walk@^3.0.3:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335"
+ integrity sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==
+ dependencies:
+ minimatch "^3.0.4"
+
+ignore@^5.0.4, ignore@^5.1.1, ignore@^5.2.4:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
+ integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
+
+immer@9.0.19:
+ version "9.0.19"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.19.tgz#67fb97310555690b5f9cd8380d38fc0aabb6b38b"
+ integrity sha512-eY+Y0qcsB4TZKwgQzLaE/lqYMlKhv5J9dyd2RhhtGhNo2njPXDqU9XPfcNfa3MIDsdtZt5KlkIsirlo4dHsWdQ==
+
+immer@^9.0.21, immer@^9.0.6:
+ version "9.0.21"
+ resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
+ integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
+
+import-fresh@^3.2.1, import-fresh@^3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
+ integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
+ dependencies:
+ parent-module "^1.0.0"
+ resolve-from "^4.0.0"
+
+import-lazy@~4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153"
+ integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==
+
+imurmurhash@^0.1.4:
+ version "0.1.4"
+ resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+ integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==
+
+indent-string@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+ integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
+inflation@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.1.0.tgz#9214db11a47e6f756d111c4f9df96971c60f886c"
+ integrity sha512-t54PPJHG1Pp7VQvxyVCJ9mBbjG3Hqryges9bXoOO6GExCPa+//i/d5GSuFtpx3ALLd7lgIAur6zrIlBQyJuMlQ==
+
+inflight@^1.0.4:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+ integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
+ dependencies:
+ once "^1.3.0"
+ wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+ integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.3:
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+ integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
+
+ini@4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.1.tgz#d95b3d843b1e906e56d6747d5447904ff50ce7a1"
+ integrity sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==
+
+ini@^1.3.4, ini@~1.3.0:
+ version "1.3.8"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
+ integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
+
+ini@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5"
+ integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==
+
+inquirer@8.2.5:
+ version "8.2.5"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8"
+ integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.1"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.21"
+ mute-stream "0.0.8"
+ ora "^5.4.1"
+ run-async "^2.4.0"
+ rxjs "^7.5.5"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+ wrap-ansi "^7.0.0"
+
+inquirer@^7.1.0:
+ version "7.3.3"
+ resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003"
+ integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==
+ dependencies:
+ ansi-escapes "^4.2.1"
+ chalk "^4.1.0"
+ cli-cursor "^3.1.0"
+ cli-width "^3.0.0"
+ external-editor "^3.0.3"
+ figures "^3.0.0"
+ lodash "^4.17.19"
+ mute-stream "0.0.8"
+ run-async "^2.4.0"
+ rxjs "^6.6.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+ through "^2.3.6"
+
+interpret@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
+ integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
+
+interpret@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
+ integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
+
+intl-messageformat@10.3.4:
+ version "10.3.4"
+ resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.3.4.tgz#20f064c28b46fa6d352a4c4ba5e9bfc597af3eba"
+ integrity sha512-/FxUIrlbPtuykSNX85CB5sp2FjLVeTmdD7TfRkVFPft2n4FgcSlAcilFytYiFAEmPHc+0PvpLCIPXeaGFzIvOg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/fast-memoize" "2.0.1"
+ "@formatjs/icu-messageformat-parser" "2.3.1"
+ tslib "^2.4.0"
+
+invariant@^2.2.4:
+ version "2.2.4"
+ resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+ integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+ dependencies:
+ loose-envify "^1.0.0"
+
+ipaddr.js@^2.0.1:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8"
+ integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==
+
+is-absolute@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-1.0.0.tgz#395e1ae84b11f26ad1795e73c17378e48a301576"
+ integrity sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==
+ dependencies:
+ is-relative "^1.0.0"
+ is-windows "^1.0.1"
+
+is-accessor-descriptor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz#3223b10628354644b86260db29b3e693f5ceedd4"
+ integrity sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA==
+ dependencies:
+ hasown "^2.0.0"
+
+is-arguments@^1.0.4:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b"
+ integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==
+ dependencies:
+ call-bind "^1.0.2"
+ has-tostringtag "^1.0.0"
+
+is-arrayish@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+ integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
+
+is-arrayish@^0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
+ integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
+
+is-binary-path@~2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
+ integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
+ dependencies:
+ binary-extensions "^2.0.0"
+
+is-buffer@^1.1.5:
+ version "1.1.6"
+ resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+ integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-callable@^1.1.3:
+ version "1.2.7"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055"
+ integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
+
+is-class-hotfix@~0.0.6:
+ version "0.0.6"
+ resolved "https://registry.yarnpkg.com/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz#a527d31fb23279281dde5f385c77b5de70a72435"
+ integrity sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==
+
+is-core-module@^2.13.0:
+ version "2.14.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.14.0.tgz#43b8ef9f46a6a08888db67b1ffd4ec9e3dfd59d1"
+ integrity sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==
+ dependencies:
+ hasown "^2.0.2"
+
+is-data-descriptor@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb"
+ integrity sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw==
+ dependencies:
+ hasown "^2.0.0"
+
+is-descriptor@^0.1.0:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.7.tgz#2727eb61fd789dcd5bdf0ed4569f551d2fe3be33"
+ integrity sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg==
+ dependencies:
+ is-accessor-descriptor "^1.0.1"
+ is-data-descriptor "^1.0.1"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.3.tgz#92d27cb3cd311c4977a4db47df457234a13cb306"
+ integrity sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw==
+ dependencies:
+ is-accessor-descriptor "^1.0.1"
+ is-data-descriptor "^1.0.1"
+
+is-docker@2.2.1, is-docker@^2.0.0, is-docker@^2.1.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa"
+ integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
+
+is-docker@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200"
+ integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+ integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==
+
+is-extendable@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+ integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+ dependencies:
+ is-plain-object "^2.0.4"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+ integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
+
+is-fullwidth-code-point@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
+ integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
+
+is-generator-function@^1.0.7:
+ version "1.0.10"
+ resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72"
+ integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==
+ dependencies:
+ has-tostringtag "^1.0.0"
+
+is-glob@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+ integrity sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw==
+ dependencies:
+ is-extglob "^2.1.0"
+
+is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
+ integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
+ dependencies:
+ is-extglob "^2.1.1"
+
+is-hotkey@^0.1.6:
+ version "0.1.8"
+ resolved "https://registry.yarnpkg.com/is-hotkey/-/is-hotkey-0.1.8.tgz#6b1f4b2d0e5639934e20c05ed24d623a21d36d25"
+ integrity sha512-qs3NZ1INIS+H+yeo7cD9pDfwYV/jqRh1JG9S9zYrNudkoUQg7OL7ziXqRKu+InFjUIDoP2o6HIkLYMh1pcWgyQ==
+
+is-inside-container@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4"
+ integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==
+ dependencies:
+ is-docker "^3.0.0"
+
+is-interactive@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e"
+ integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==
+
+is-lower-case@^1.1.0:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-1.1.3.tgz#7e147be4768dc466db3bfb21cc60b31e6ad69393"
+ integrity sha512-+5A1e/WJpLLXZEDlgz4G//WYSHyQBD32qa4Jd3Lw06qQlv3fJHnp3YIHjTQSGzHMgzmVKz2ZP3rBxTHkPw/lxA==
+ dependencies:
+ lower-case "^1.1.0"
+
+is-nan@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d"
+ integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
+ dependencies:
+ call-bind "^1.0.0"
+ define-properties "^1.1.3"
+
+is-number@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+ integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg==
+ dependencies:
+ kind-of "^3.0.2"
+
+is-number@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+ integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
+
+is-obj@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
+ integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
+
+is-path-cwd@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
+ integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
+
+is-path-inside@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
+ integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
+
+is-plain-obj@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0"
+ integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+ integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+ dependencies:
+ isobject "^3.0.1"
+
+is-plain-object@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344"
+ integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==
+
+is-relative@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-1.0.0.tgz#a1bb6935ce8c5dba1e8b9754b9b2dcc020e2260d"
+ integrity sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==
+ dependencies:
+ is-unc-path "^1.0.0"
+
+is-retry-allowed@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz#88f34cbd236e043e71b6932d09b0c65fb7b4d71d"
+ integrity sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==
+
+is-ssh@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2"
+ integrity sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==
+ dependencies:
+ protocols "^2.0.1"
+
+is-stream@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
+ integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==
+
+is-stream@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac"
+ integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==
+
+is-type-of@^1.2.1:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/is-type-of/-/is-type-of-1.4.0.tgz#3ed175a0eee888b1da4983332e7714feb8a8fb2b"
+ integrity sha512-EddYllaovi5ysMLMEN7yzHEKh8A850cZ7pykrY1aNRQGn/CDjRDE9qEWbIdt7xGEVJmjBXzU/fNnC4ABTm8tEQ==
+ dependencies:
+ core-util-is "^1.0.2"
+ is-class-hotfix "~0.0.6"
+ isstream "~0.1.2"
+
+is-typed-array@^1.1.3:
+ version "1.1.13"
+ resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229"
+ integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==
+ dependencies:
+ which-typed-array "^1.1.14"
+
+is-typedarray@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+ integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==
+
+is-unc-path@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-1.0.0.tgz#d731e8898ed090a12c352ad2eaed5095ad322c9d"
+ integrity sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==
+ dependencies:
+ unc-path-regex "^0.1.2"
+
+is-unicode-supported@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7"
+ integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==
+
+is-upper-case@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-1.1.2.tgz#8d0b1fa7e7933a1e58483600ec7d9661cbaf756f"
+ integrity sha512-GQYSJMgfeAmVwh9ixyk888l7OIhNAGKtY6QA+IrWlu9MDTCaXmeozOZ2S9Knj7bQwBO/H6J2kb+pbyTUiMNbsw==
+ dependencies:
+ upper-case "^1.1.0"
+
+is-windows@^1.0.1, is-windows@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+ integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+is-wsl@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271"
+ integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
+ dependencies:
+ is-docker "^2.0.0"
+
+isarray@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
+ integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==
+
+isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
+ integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==
+
+isbinaryfile@^4.0.2:
+ version "4.0.10"
+ resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3"
+ integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==
+
+isexe@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+ integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+
+isobject@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+ integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA==
+ dependencies:
+ isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+ integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==
+
+isows@1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/isows/-/isows-1.0.4.tgz#810cd0d90cc4995c26395d2aa4cfa4037ebdf061"
+ integrity sha512-hEzjY+x9u9hPmBom9IIAqdJCwNLax+xrPb51vEPpERoFlIxgmZcHzsT5jKG06nvInKOBGvReAVz80Umed5CczQ==
+
+isstream@^0.1.2, isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+ integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
+
+jackspeak@^3.1.2:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.0.tgz#a75763ff36ad778ede6a156d8ee8b124de445b4a"
+ integrity sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==
+ dependencies:
+ "@isaacs/cliui" "^8.0.2"
+ optionalDependencies:
+ "@pkgjs/parseargs" "^0.11.0"
+
+jest-worker@^27.4.5:
+ version "27.5.1"
+ resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0"
+ integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==
+ dependencies:
+ "@types/node" "*"
+ merge-stream "^2.0.0"
+ supports-color "^8.0.0"
+
+jju@~1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a"
+ integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==
+
+jmespath@0.16.0:
+ version "0.16.0"
+ resolved "https://registry.yarnpkg.com/jmespath/-/jmespath-0.16.0.tgz#b15b0a85dfd4d930d43e69ed605943c802785076"
+ integrity sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==
+
+jose@^4.14.6:
+ version "4.15.7"
+ resolved "https://registry.yarnpkg.com/jose/-/jose-4.15.7.tgz#96ad68d786632bd03c9068aa281810dbbe1b60d8"
+ integrity sha512-L7ioP+JAuZe8v+T5+zVI9Tx8LtU8BL7NxkyDFVMv+Qr3JW0jSoYDedLtodaXwfqMpeCyx4WXFNyu9tJt4WvC1A==
+
+joycon@^3.0.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03"
+ integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==
+
+js-cookie@2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
+ integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
+
+js-sha3@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+ integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+ integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-tokens@^9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-9.0.0.tgz#0f893996d6f3ed46df7f0a3b12a03f5fd84223c1"
+ integrity sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==
+
+js-yaml@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
+ integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
+ dependencies:
+ argparse "^2.0.1"
+
+jsesc@^2.5.1:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+ integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+json-buffer@3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13"
+ integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==
+
+json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+ integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
+
+json-schema-traverse@^0.4.1:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+ integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema-traverse@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
+ integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+
+json-stream@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/json-stream/-/json-stream-1.0.0.tgz#1a3854e28d2bbeeab31cc7ddf683d2ddc5652708"
+ integrity sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg==
+
+json5@^2.1.2, json5@^2.2.0:
+ version "2.2.3"
+ resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283"
+ integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==
+
+jsonfile@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+ integrity sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jsonfile@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
+ integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
+ dependencies:
+ universalify "^2.0.0"
+ optionalDependencies:
+ graceful-fs "^4.1.6"
+
+jsonwebtoken@9.0.0:
+ version "9.0.0"
+ resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz#d0faf9ba1cc3a56255fe49c0961a67e520c1926d"
+ integrity sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==
+ dependencies:
+ jws "^3.2.2"
+ lodash "^4.17.21"
+ ms "^2.1.1"
+ semver "^7.3.8"
+
+jwa@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a"
+ integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==
+ dependencies:
+ buffer-equal-constant-time "1.0.1"
+ ecdsa-sig-formatter "1.0.11"
+ safe-buffer "^5.0.1"
+
+jwa@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc"
+ integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==
+ dependencies:
+ buffer-equal-constant-time "1.0.1"
+ ecdsa-sig-formatter "1.0.11"
+ safe-buffer "^5.0.1"
+
+jwk-to-pem@2.0.5, jwk-to-pem@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/jwk-to-pem/-/jwk-to-pem-2.0.5.tgz#151310bcfbcf731adc5ad9f379cbc8b395742906"
+ integrity sha512-L90jwellhO8jRKYwbssU9ifaMVqajzj3fpRjDKcsDzrslU9syRbFqfkXtT4B89HYAap+xsxNcxgBSB09ig+a7A==
+ dependencies:
+ asn1.js "^5.3.0"
+ elliptic "^6.5.4"
+ safe-buffer "^5.0.1"
+
+jwks-rsa@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/jwks-rsa/-/jwks-rsa-3.1.0.tgz#50406f23e38c9b2682cd437f824d7d61aa983171"
+ integrity sha512-v7nqlfezb9YfHHzYII3ef2a2j1XnGeSE/bK3WfumaYCqONAIstJbrEGapz4kadScZzEt7zYCN7bucj8C0Mv/Rg==
+ dependencies:
+ "@types/express" "^4.17.17"
+ "@types/jsonwebtoken" "^9.0.2"
+ debug "^4.3.4"
+ jose "^4.14.6"
+ limiter "^1.1.5"
+ lru-memoizer "^2.2.0"
+
+jws@^3.2.2:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304"
+ integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==
+ dependencies:
+ jwa "^1.4.1"
+ safe-buffer "^5.0.1"
+
+jws@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4"
+ integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==
+ dependencies:
+ jwa "^2.0.0"
+ safe-buffer "^5.0.1"
+
+keygrip@~1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.1.0.tgz#871b1681d5e159c62a445b0c74b615e0917e7226"
+ integrity sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==
+ dependencies:
+ tsscmp "1.0.6"
+
+keyv@^4.0.0:
+ version "4.5.4"
+ resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93"
+ integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==
+ dependencies:
+ json-buffer "3.0.1"
+
+kind-of@^3.0.2, kind-of@^3.0.3:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+ integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ==
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+ integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw==
+ dependencies:
+ is-buffer "^1.1.5"
+
+kind-of@^6.0.2:
+ version "6.0.3"
+ resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
+ integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
+
+kleur@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
+ integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
+
+knex@2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/knex/-/knex-2.5.0.tgz#5c99245e9c7e6a9d1a8b7fcf48b457ccb471dec3"
+ integrity sha512-h6Ru3PJmZjCDUEqLgwQ/RJUu06Bz7MTzY6sD90udLIa9qwtC7Rnicr7TBiWSaswZmDqk4EZ8xysdg1fkvhYM6w==
+ dependencies:
+ colorette "2.0.19"
+ commander "^10.0.0"
+ debug "4.3.4"
+ escalade "^3.1.1"
+ esm "^3.2.25"
+ get-package-type "^0.1.0"
+ getopts "2.3.0"
+ interpret "^2.2.0"
+ lodash "^4.17.21"
+ pg-connection-string "2.6.1"
+ rechoir "^0.8.0"
+ resolve-from "^5.0.0"
+ tarn "^3.0.2"
+ tildify "2.0.0"
+
+koa-body@4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/koa-body/-/koa-body-4.2.0.tgz#37229208b820761aca5822d14c5fc55cee31b26f"
+ integrity sha512-wdGu7b9amk4Fnk/ytH8GuWwfs4fsB5iNkY8kZPpgQVb04QZSv85T0M8reb+cJmvLE8cjPYvBzRikD3s6qz8OoA==
+ dependencies:
+ "@types/formidable" "^1.0.31"
+ co-body "^5.1.1"
+ formidable "^1.1.1"
+
+koa-bodyparser@4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/koa-bodyparser/-/koa-bodyparser-4.4.1.tgz#a908d848e142cc57d9eece478e932bf00dce3029"
+ integrity sha512-kBH3IYPMb+iAXnrxIhXnW+gXV8OTzCu8VPDqvcDHW9SQrbkHmqPQtiZwrltNmSq6/lpipHnT7k7PsjlVD7kK0w==
+ dependencies:
+ co-body "^6.0.0"
+ copy-to "^2.0.1"
+ type-is "^1.6.18"
+
+koa-compose@4.1.0, koa-compose@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-4.1.0.tgz#507306b9371901db41121c812e923d0d67d3e877"
+ integrity sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==
+
+koa-compress@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/koa-compress/-/koa-compress-5.1.0.tgz#7b9fe24f4c1b28d9cae90864597da472c2fcf701"
+ integrity sha512-G3Ppo9jrUwlchp6qdoRgQNMiGZtM0TAHkxRZQ7EoVvIG8E47J4nAsMJxXHAUQ+0oc7t0MDxSdONWTFcbzX7/Bg==
+ dependencies:
+ bytes "^3.0.0"
+ compressible "^2.0.0"
+ http-errors "^1.8.0"
+ koa-is-json "^1.0.0"
+ statuses "^2.0.1"
+
+koa-convert@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-2.0.0.tgz#86a0c44d81d40551bae22fee6709904573eea4f5"
+ integrity sha512-asOvN6bFlSnxewce2e/DK3p4tltyfC4VM7ZwuTuepI7dEQVcvpyFuBcEARu1+Hxg8DIwytce2n7jrZtRlPrARA==
+ dependencies:
+ co "^4.6.0"
+ koa-compose "^4.1.0"
+
+koa-favicon@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/koa-favicon/-/koa-favicon-2.1.0.tgz#c430cc594614fb494adcb5ee1196a2f7f53ea442"
+ integrity sha512-LvukcooYjxKtnZq0RXdBup+JDhaHwLgnLlDHB/xvjwQEjbc4rbp/0WkmOzpOvaHujc+fIwPear0dpKX1V+dHVg==
+ dependencies:
+ mz "^2.7.0"
+
+koa-helmet@7.0.2:
+ version "7.0.2"
+ resolved "https://registry.yarnpkg.com/koa-helmet/-/koa-helmet-7.0.2.tgz#2077e60cc69fa550802931ccdb85f948aa6bd054"
+ integrity sha512-AvzS6VuEfFgbAm0mTUnkk/BpMarMcs5A56g+f0sfrJ6m63wII48d2GDrnUQGp0Nj+RR950vNtgqXm9UJSe7GOg==
+ dependencies:
+ helmet "^6.0.1"
+
+koa-ip@^2.1.2:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/koa-ip/-/koa-ip-2.1.3.tgz#b7318bb30fd1e06d03a96beb704ee72cc6ecade0"
+ integrity sha512-QLVBByImwDq9enZXVOD3Astk876B7N0IYta7Kik4iyNB462rVzBB1/LD0Ek1F+v9nGUTHBFyhh8043EIlskK9Q==
+ dependencies:
+ debug "4.3.4"
+ lodash.isplainobject "4.0.6"
+ request-ip "3.3.0"
+
+koa-is-json@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14"
+ integrity sha512-+97CtHAlWDx0ndt0J8y3P12EWLwTLMXIfMnYDev3wOTwH/RpBGMlfn4bDXlMEg1u73K6XRE9BbUp+5ZAYoRYWw==
+
+koa-passport@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-5.0.0.tgz#66c8e91b06358969ab6129d90368fa07a06fafc0"
+ integrity sha512-eNGg3TGgZ4ydm9DYCOqaa0ySSA/44BS6X+v4CKjP/nHOoXlADRonHsZvS3QWok6EV0ZL0V7FhfWxRYfD2B5kTQ==
+ dependencies:
+ passport "^0.6.0"
+
+koa-range@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/koa-range/-/koa-range-0.3.0.tgz#3588e3496473a839a1bd264d2a42b1d85bd7feac"
+ integrity sha512-Ich3pCz6RhtbajYXRWjIl6O5wtrLs6kE3nkXc9XmaWe+MysJyZO7K4L3oce1Jpg/iMgCbj+5UCiMm/rqVtcDIg==
+ dependencies:
+ stream-slice "^0.1.2"
+
+koa-send@^5.0.0:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-5.0.1.tgz#39dceebfafb395d0d60beaffba3a70b4f543fe79"
+ integrity sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==
+ dependencies:
+ debug "^4.1.1"
+ http-errors "^1.7.3"
+ resolve-path "^1.4.0"
+
+koa-session@6.4.0:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/koa-session/-/koa-session-6.4.0.tgz#f17c6f1844b37114192aa23a0ccf4f58c3042e96"
+ integrity sha512-h/dxmSOvNEXpHQPRs4TV03TZVFyZIjmYQiTAW5JBFTYBOZ0VdpZ8QEE6Dud75g8z9JNGXi3m++VqRmqToB+c2A==
+ dependencies:
+ crc "^3.8.0"
+ debug "^4.3.3"
+ is-type-of "^1.2.1"
+ uuid "^8.3.2"
+
+koa-static@5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/koa-static/-/koa-static-5.0.0.tgz#5e92fc96b537ad5219f425319c95b64772776943"
+ integrity sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==
+ dependencies:
+ debug "^3.1.0"
+ koa-send "^5.0.0"
+
+koa2-ratelimit@^1.1.2:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/koa2-ratelimit/-/koa2-ratelimit-1.1.3.tgz#9f839c4f5533151aa4d5b8d11381a9a07854f0ff"
+ integrity sha512-gdrIw6m/D7pmScScL4dz50qLbRR3UGqvO1Vuy2dc7hVIuFAl1OVTnu6WFyEJ5GbfyLZFaCMWzRw6t4krvzvUTg==
+
+koa@2.13.4:
+ version "2.13.4"
+ resolved "https://registry.yarnpkg.com/koa/-/koa-2.13.4.tgz#ee5b0cb39e0b8069c38d115139c774833d32462e"
+ integrity sha512-43zkIKubNbnrULWlHdN5h1g3SEKXOEzoAlRsHOTFpnlDu8JlAOZSMJBLULusuXRequboiwJcj5vtYXKB3k7+2g==
+ dependencies:
+ accepts "^1.3.5"
+ cache-content-type "^1.0.0"
+ content-disposition "~0.5.2"
+ content-type "^1.0.4"
+ cookies "~0.8.0"
+ debug "^4.3.2"
+ delegates "^1.0.0"
+ depd "^2.0.0"
+ destroy "^1.0.4"
+ encodeurl "^1.0.2"
+ escape-html "^1.0.3"
+ fresh "~0.5.2"
+ http-assert "^1.3.0"
+ http-errors "^1.6.3"
+ is-generator-function "^1.0.7"
+ koa-compose "^4.1.0"
+ koa-convert "^2.0.0"
+ on-finished "^2.3.0"
+ only "~0.0.2"
+ parseurl "^1.3.2"
+ statuses "^1.5.0"
+ type-is "^1.6.16"
+ vary "^1.1.2"
+
+kuler@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3"
+ integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==
+
+libbase64@0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/libbase64/-/libbase64-0.1.0.tgz#62351a839563ac5ff5bd26f12f60e9830bb751e6"
+ integrity sha512-B91jifmFw1DKEqEWstSpg1PbtUbBzR4yQAPT86kCQXBtud1AJVA+Z6RSklSrqmKe4q2eiEufgnhqJKPgozzfIQ==
+
+libmime@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/libmime/-/libmime-2.1.0.tgz#51bc76de2283161eb9051c4bc80aed713e4fd1cd"
+ integrity sha512-4be2R6/jOasyPTw0BkpIZBVk2cElqjdIdS0PRPhbOCV4wWuL/ZcYYpN1BCTVB+6eIQ0uuAwp5hQTHFrM5Joa8w==
+ dependencies:
+ iconv-lite "0.4.13"
+ libbase64 "0.1.0"
+ libqp "1.1.0"
+
+libmime@^2.0.3:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/libmime/-/libmime-2.1.3.tgz#25017ca5ab5a1e98aadbe2725017cf1d48a42a0c"
+ integrity sha512-ABr2f4O+K99sypmkF/yPz2aXxUFHEZzv+iUkxItCeKZWHHXdQPpDXd6rV1kBBwL4PserzLU09EIzJ2lxC9hPfQ==
+ dependencies:
+ iconv-lite "0.4.15"
+ libbase64 "0.1.0"
+ libqp "1.1.0"
+
+libqp@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8"
+ integrity sha512-4Rgfa0hZpG++t1Vi2IiqXG9Ad1ig4QTmtuZF946QJP4bPqOYC78ixUXgz5TW/wE7lNaNKlplSYTxQ+fR2KZ0EA==
+
+liftoff@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.5.0.tgz#2009291bb31cea861bbf10a7c15a28caf75c31ec"
+ integrity sha512-01zfGFqfORP1CGmZZP2Zn51zsqz4RltDi0RDOhbGoLYdUT5Lw+I2gX6QdwXhPITF6hPOHEOp+At6/L24hIg9WQ==
+ dependencies:
+ extend "^3.0.0"
+ findup-sync "^2.0.0"
+ fined "^1.0.1"
+ flagged-respawn "^1.0.0"
+ is-plain-object "^2.0.4"
+ object.map "^1.0.0"
+ rechoir "^0.6.2"
+ resolve "^1.1.7"
+
+limiter@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/limiter/-/limiter-1.1.5.tgz#8f92a25b3b16c6131293a0cc834b4a838a2aa7c2"
+ integrity sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==
+
+lines-and-columns@^1.1.6:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
+ integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
+
+linkify-it@^3.0.1:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-3.0.3.tgz#a98baf44ce45a550efb4d49c769d07524cc2fa2e"
+ integrity sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==
+ dependencies:
+ uc.micro "^1.0.1"
+
+loader-runner@^4.2.0:
+ version "4.3.0"
+ resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1"
+ integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==
+
+loader-utils@^2.0.0, loader-utils@^2.0.4:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c"
+ integrity sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==
+ dependencies:
+ big.js "^5.2.2"
+ emojis-list "^3.0.0"
+ json5 "^2.1.2"
+
+local-pkg@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.5.0.tgz#093d25a346bae59a99f80e75f6e9d36d7e8c925c"
+ integrity sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==
+ dependencies:
+ mlly "^1.4.2"
+ pkg-types "^1.0.3"
+
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
+locate-path@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
+ integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
+ dependencies:
+ p-locate "^4.1.0"
+
+locate-path@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"
+ integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==
+ dependencies:
+ p-locate "^5.0.0"
+
+lodash-es@^4.17.15, lodash-es@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
+ integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
+
+lodash.clonedeep@^4.5.0:
+ version "4.5.0"
+ resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
+ integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==
+
+lodash.deburr@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/lodash.deburr/-/lodash.deburr-4.1.0.tgz#ddb1bbb3ef07458c0177ba07de14422cb033ff9b"
+ integrity sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==
+
+lodash.get@^4.4.2:
+ version "4.4.2"
+ resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
+ integrity sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==
+
+lodash.isplainobject@4.0.6:
+ version "4.0.6"
+ resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
+ integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==
+
+lodash@4.17.21, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
+log-symbols@^2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
+ integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==
+ dependencies:
+ chalk "^2.0.1"
+
+log-symbols@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503"
+ integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==
+ dependencies:
+ chalk "^4.1.0"
+ is-unicode-supported "^0.1.0"
+
+logform@^2.3.2, logform@^2.4.0:
+ version "2.6.0"
+ resolved "https://registry.yarnpkg.com/logform/-/logform-2.6.0.tgz#8c82a983f05d6eaeb2d75e3decae7a768b2bf9b5"
+ integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==
+ dependencies:
+ "@colors/colors" "1.6.0"
+ "@types/triple-beam" "^1.3.2"
+ fecha "^4.2.0"
+ ms "^2.1.1"
+ safe-stable-stringify "^2.3.1"
+ triple-beam "^1.3.0"
+
+long-timeout@0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/long-timeout/-/long-timeout-0.1.1.tgz#9721d788b47e0bcb5a24c2e2bee1a0da55dab514"
+ integrity sha512-BFRuQUqc7x2NWxfJBCyUrN8iYUYznzL9JROmRz1gZ6KlOIgmoD+njPVbb+VNn2nGMKggMsK79iUNErillsrx7w==
+
+loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
+loupe@^2.3.6, loupe@^2.3.7:
+ version "2.3.7"
+ resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697"
+ integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==
+ dependencies:
+ get-func-name "^2.0.1"
+
+lower-case-first@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
+ integrity sha512-UuxaYakO7XeONbKrZf5FEgkantPf5DUqDayzP5VXZrtRPdH86s4kN47I8B3TW10S4QKiE3ziHNf3kRN//okHjA==
+ dependencies:
+ lower-case "^1.1.2"
+
+lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+ integrity sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==
+
+lower-case@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
+ integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
+ dependencies:
+ tslib "^2.0.3"
+
+lowercase-keys@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
+ integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
+
+lru-cache@6.0.0, lru-cache@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
+ integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
+ dependencies:
+ yallist "^4.0.0"
+
+lru-cache@^10.2.0:
+ version "10.2.2"
+ resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.2.tgz#48206bc114c1252940c41b25b41af5b545aca878"
+ integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==
+
+lru-memoizer@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/lru-memoizer/-/lru-memoizer-2.3.0.tgz#ef0fbc021bceb666794b145eefac6be49dc47f31"
+ integrity sha512-GXn7gyHAMhO13WSKrIiNfztwxodVsP8IoZ3XfrJV4yH2x0/OeTO/FIaAHTY5YekdGgW94njfuKmyyt1E0mR6Ug==
+ dependencies:
+ lodash.clonedeep "^4.5.0"
+ lru-cache "6.0.0"
+
+lru_map@^0.3.3:
+ version "0.3.3"
+ resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd"
+ integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ==
+
+luxon@^1.26.0:
+ version "1.28.1"
+ resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.28.1.tgz#528cdf3624a54506d710290a2341aa8e6e6c61b0"
+ integrity sha512-gYHAa180mKrNIUJCbwpmD0aTu9kV0dREDrwNnuyFAsO1Wt0EVYSZelPnJlbj9HplzXX/YWXHFTL45kvZ53M0pw==
+
+magic-string@^0.30.5:
+ version "0.30.10"
+ resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.10.tgz#123d9c41a0cb5640c892b041d4cfb3bd0aa4b39e"
+ integrity sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==
+ dependencies:
+ "@jridgewell/sourcemap-codec" "^1.4.15"
+
+mailcomposer@3.12.0:
+ version "3.12.0"
+ resolved "https://registry.yarnpkg.com/mailcomposer/-/mailcomposer-3.12.0.tgz#9c5e1188aa8e1c62ec8b86bd43468102b639e8f9"
+ integrity sha512-zBeDoKUTNI8IAsazoMQFt3eVSVRtDtgrvBjBVdBjxDEX+5KLlKtEFCrBXnxPhs8aTYufUS1SmbFnGpjHS53deg==
+ dependencies:
+ buildmail "3.10.0"
+ libmime "2.1.0"
+
+make-dir@^3.0.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
+ integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
+ dependencies:
+ semver "^6.0.0"
+
+make-iterator@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/make-iterator/-/make-iterator-1.0.1.tgz#29b33f312aa8f547c4a5e490f56afcec99133ad6"
+ integrity sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==
+ dependencies:
+ kind-of "^6.0.2"
+
+map-cache@^0.2.0, map-cache@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+ integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==
+
+map-visit@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+ integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w==
+ dependencies:
+ object-visit "^1.0.0"
+
+markdown-it-abbr@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz#d66b5364521cbb3dd8aa59dadfba2fb6865c8fd8"
+ integrity sha512-ZeA4Z4SaBbYysZap5iZcxKmlPL6bYA8grqhzJIHB1ikn7njnzaP8uwbtuXc4YXD5LicI4/2Xmc0VwmSiFV04gg==
+
+markdown-it-container@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-container/-/markdown-it-container-3.0.0.tgz#1d19b06040a020f9a827577bb7dbf67aa5de9a5b"
+ integrity sha512-y6oKTq4BB9OQuY/KLfk/O3ysFhB3IMYoIWhGJEidXt1NQFocFK2sA2t0NYZAMyMShAGL6x5OPIbrmXPIqaN9rw==
+
+markdown-it-deflist@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-deflist/-/markdown-it-deflist-2.1.0.tgz#50d7a56b9544cd81252f7623bd785e28a8dcef5c"
+ integrity sha512-3OuqoRUlSxJiuQYu0cWTLHNhhq2xtoSFqsZK8plANg91+RJQU1ziQ6lA2LzmFAEes18uPBsHZpcX6We5l76Nzg==
+
+markdown-it-emoji@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-2.0.2.tgz#cd42421c2fda1537d9cc12b9923f5c8aeb9029c8"
+ integrity sha512-zLftSaNrKuYl0kR5zm4gxXjHaOI3FAOEaloKmRA5hijmJZvSjmxcokOLlzycb/HXlUFWzXqpIEoyEMCE4i9MvQ==
+
+markdown-it-footnote@^3.0.3:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.3.tgz#e0e4c0d67390a4c5f0c75f73be605c7c190ca4d8"
+ integrity sha512-YZMSuCGVZAjzKMn+xqIco9d1cLGxbELHZ9do/TSYVzraooV8ypsppKNmUJ0fVH5ljkCInQAtFpm8Rb3eXSrt5w==
+
+markdown-it-ins@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/markdown-it-ins/-/markdown-it-ins-3.0.1.tgz#c09356b917cf1dbf73add0b275d67ab8c73d4b4d"
+ integrity sha512-32SSfZqSzqyAmmQ4SHvhxbFqSzPDqsZgMHDwxqPzp+v+t8RsmqsBZRG+RfRQskJko9PfKC2/oxyOs4Yg/CfiRw==
+
+markdown-it-mark@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/markdown-it-mark/-/markdown-it-mark-3.0.1.tgz#51257db58787d78aaf46dc13418d99a9f3f0ebd3"
+ integrity sha512-HyxjAu6BRsdt6Xcv6TKVQnkz/E70TdGXEFHRYBGLncRE9lBFwDNLVtFojKxjJWgJ+5XxUwLaHXy+2sGBbDn+4A==
+
+markdown-it-sub@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz#375fd6026eae7ddcb012497f6411195ea1e3afe8"
+ integrity sha512-z2Rm/LzEE1wzwTSDrI+FlPEveAAbgdAdPhdWarq/ZGJrGW/uCQbKAnhoCsE4hAbc3SEym26+W2z/VQB0cQiA9Q==
+
+markdown-it-sup@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz#cb9c9ff91a5255ac08f3fd3d63286e15df0a1fc3"
+ integrity sha512-E32m0nV9iyhRR7CrhnzL5msqic7rL1juWre6TQNxsnApg7Uf+F97JOKxUijg5YwXz86lZ0mqfOnutoryyNdntQ==
+
+markdown-it@^12.3.2:
+ version "12.3.2"
+ resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-12.3.2.tgz#bf92ac92283fe983fe4de8ff8abfb5ad72cd0c90"
+ integrity sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==
+ dependencies:
+ argparse "^2.0.1"
+ entities "~2.1.0"
+ linkify-it "^3.0.1"
+ mdurl "^1.0.1"
+ uc.micro "^1.0.5"
+
+match-sorter@^6.0.2:
+ version "6.3.4"
+ resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.4.tgz#afa779d8e922c81971fbcb4781c7003ace781be7"
+ integrity sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==
+ dependencies:
+ "@babel/runtime" "^7.23.8"
+ remove-accents "0.5.0"
+
+mdurl@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
+ integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==
+
+media-typer@0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+ integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
+
+memfs@^3.4.1, memfs@^3.4.12:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.6.0.tgz#d7a2110f86f79dd950a8b6df6d57bc984aa185f6"
+ integrity sha512-EGowvkkgbMcIChjMTMkESFDbZeSh8xZ7kNSF0hAiAN4Jh6jgHCRS0Ga/+C8y6Au+oqpezRHCfPsmJ2+DwAgiwQ==
+ dependencies:
+ fs-monkey "^1.0.4"
+
+"memoize-one@>=3.1.1 <6":
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e"
+ integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==
+
+memoize-one@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
+ integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
+
+merge-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
+ integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
+
+merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
+ integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
+
+methods@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+ integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==
+
+micromatch@^3.0.4:
+ version "3.1.10"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+ integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ braces "^2.3.1"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ extglob "^2.0.4"
+ fragment-cache "^0.2.1"
+ kind-of "^6.0.2"
+ nanomatch "^1.2.9"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.2"
+
+micromatch@^4.0.4:
+ version "4.0.7"
+ resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5"
+ integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==
+ dependencies:
+ braces "^3.0.3"
+ picomatch "^2.3.1"
+
+microseconds@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
+ integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
+
+mime-db@1.52.0, "mime-db@>= 1.43.0 < 2":
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@2.1.35, mime-types@^2.1.12, mime-types@^2.1.18, mime-types@^2.1.27, mime-types@^2.1.28, mime-types@^2.1.31, mime-types@^2.1.35, mime-types@~2.1.24, mime-types@~2.1.34:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
+mimic-fn@^1.0.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+ integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+
+mimic-fn@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+ integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+mimic-fn@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc"
+ integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==
+
+mimic-response@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
+ integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
+
+mimic-response@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
+ integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
+
+mini-css-extract-plugin@2.7.7:
+ version "2.7.7"
+ resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.7.tgz#4acf02f362c641c38fb913bfcb7ca2fc4a7cf339"
+ integrity sha512-+0n11YGyRavUR3IlaOzJ0/4Il1avMvJ1VJfhWfCn24ITQXhRr1gghbhhrda6tgtNcpZaWKdSuwKq20Jb7fnlyw==
+ dependencies:
+ schema-utils "^4.0.0"
+
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+ integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimalistic-crypto-utils@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+ integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==
+
+minimatch@9.0.3:
+ version "9.0.3"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
+ integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
+ integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
+ dependencies:
+ brace-expansion "^1.1.7"
+
+minimatch@^5.0.1:
+ version "5.1.6"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96"
+ integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimatch@^9.0.4:
+ version "9.0.4"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.4.tgz#8e49c731d1749cbec05050ee5145147b32496a51"
+ integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==
+ dependencies:
+ brace-expansion "^2.0.1"
+
+minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c"
+ integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==
+
+minio@7.1.3:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/minio/-/minio-7.1.3.tgz#86dc95f3671045d6956920db757bb63f25bf20ee"
+ integrity sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==
+ dependencies:
+ async "^3.2.4"
+ block-stream2 "^2.1.0"
+ browser-or-node "^2.1.1"
+ buffer-crc32 "^0.2.13"
+ fast-xml-parser "^4.2.2"
+ ipaddr.js "^2.0.1"
+ json-stream "^1.0.0"
+ lodash "^4.17.21"
+ mime-types "^2.1.35"
+ query-string "^7.1.3"
+ through2 "^4.0.2"
+ web-encoding "^1.1.5"
+ xml "^1.0.1"
+ xml2js "^0.5.0"
+
+minipass@^3.0.0:
+ version "3.3.6"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a"
+ integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==
+ dependencies:
+ yallist "^4.0.0"
+
+minipass@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
+ integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
+
+"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.4, minipass@^7.1.2:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707"
+ integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==
+
+minizlib@^2.1.1:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931"
+ integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==
+ dependencies:
+ minipass "^3.0.0"
+ yallist "^4.0.0"
+
+minizlib@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.0.1.tgz#46d5329d1eb3c83924eff1d3b858ca0a31581012"
+ integrity sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==
+ dependencies:
+ minipass "^7.0.4"
+ rimraf "^5.0.5"
+
+mixin-deep@^1.2.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+ integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+ dependencies:
+ for-in "^1.0.2"
+ is-extendable "^1.0.1"
+
+mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113"
+ integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
+
+mkdirp@^0.5.1:
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
+ integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
+ dependencies:
+ minimist "^1.2.6"
+
+mkdirp@^1.0.3, mkdirp@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
+ integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
+
+mkdirp@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50"
+ integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==
+
+mlly@^1.4.2, mlly@^1.7.0:
+ version "1.7.1"
+ resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.7.1.tgz#e0336429bb0731b6a8e887b438cbdae522c8f32f"
+ integrity sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==
+ dependencies:
+ acorn "^8.11.3"
+ pathe "^1.1.2"
+ pkg-types "^1.1.1"
+ ufo "^1.5.3"
+
+mrmime@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4"
+ integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==
+
+ms@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+ integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==
+
+ms@2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+ integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+ms@^2.1.1:
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
+ integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
+
+multistream@^4.0.1:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/multistream/-/multistream-4.1.0.tgz#7bf00dfd119556fbc153cff3de4c6d477909f5a8"
+ integrity sha512-J1XDiAmmNpRCBfIWJv+n0ymC4ABcf/Pl+5YvC5B/D2f/2+8PtHvCNxMPKiQcZyi922Hq69J2YOpb1pTywfifyw==
+ dependencies:
+ once "^1.4.0"
+ readable-stream "^3.6.0"
+
+mute-stream@0.0.8:
+ version "0.0.8"
+ resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d"
+ integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==
+
+mz@^2.7.0:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
+ integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==
+ dependencies:
+ any-promise "^1.0.0"
+ object-assign "^4.0.1"
+ thenify-all "^1.0.0"
+
+nano-time@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
+ integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==
+ dependencies:
+ big-integer "^1.6.16"
+
+nanoclone@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4"
+ integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA==
+
+nanoid@^3.3.7:
+ version "3.3.7"
+ resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+ integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
+nanomatch@^1.2.9:
+ version "1.2.13"
+ resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+ integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+ dependencies:
+ arr-diff "^4.0.0"
+ array-unique "^0.3.2"
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ fragment-cache "^0.2.1"
+ is-windows "^1.0.2"
+ kind-of "^6.0.2"
+ object.pick "^1.3.0"
+ regex-not "^1.0.0"
+ snapdragon "^0.8.1"
+ to-regex "^3.0.1"
+
+napi-build-utils@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806"
+ integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==
+
+negotiator@0.6.3:
+ version "0.6.3"
+ resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd"
+ integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==
+
+neo-async@^2.6.2:
+ version "2.6.2"
+ resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
+ integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
+
+no-case@^2.2.0, no-case@^2.3.2:
+ version "2.3.2"
+ resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+ integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+ dependencies:
+ lower-case "^1.1.1"
+
+no-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
+ integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
+ dependencies:
+ lower-case "^2.0.2"
+ tslib "^2.0.3"
+
+node-abi@^3.3.0:
+ version "3.65.0"
+ resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.65.0.tgz#ca92d559388e1e9cab1680a18c1a18757cdac9d3"
+ integrity sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA==
+ dependencies:
+ semver "^7.3.5"
+
+node-abort-controller@^3.0.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548"
+ integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==
+
+node-addon-api@^2.0.0:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32"
+ integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==
+
+node-addon-api@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76"
+ integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==
+
+node-fetch@2.7.0, node-fetch@^2.6.12:
+ version "2.7.0"
+ resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
+ integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
+ dependencies:
+ whatwg-url "^5.0.0"
+
+node-gyp-build@^4.2.0:
+ version "4.8.1"
+ resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.1.tgz#976d3ad905e71b76086f4f0b0d3637fe79b6cda5"
+ integrity sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==
+
+node-machine-id@1.1.12, node-machine-id@^1.1.10:
+ version "1.1.12"
+ resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267"
+ integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==
+
+node-plop@0.26.3, node-plop@^0.26.3:
+ version "0.26.3"
+ resolved "https://registry.yarnpkg.com/node-plop/-/node-plop-0.26.3.tgz#d6fa7e71393c8b940513ba8c4868f8aaa6dea9df"
+ integrity sha512-Cov028YhBZ5aB7MdMWJEmwyBig43aGL5WT4vdoB28Oitau1zZAcHUn8Sgfk9HM33TqhtLJ9PlM/O0Mv+QpV/4Q==
+ dependencies:
+ "@babel/runtime-corejs3" "^7.9.2"
+ "@types/inquirer" "^6.5.0"
+ change-case "^3.1.0"
+ del "^5.1.0"
+ globby "^10.0.1"
+ handlebars "^4.4.3"
+ inquirer "^7.1.0"
+ isbinaryfile "^4.0.2"
+ lodash.get "^4.4.2"
+ mkdirp "^0.5.1"
+ resolve "^1.12.0"
+
+node-releases@^2.0.14:
+ version "2.0.14"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b"
+ integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==
+
+node-schedule@2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/node-schedule/-/node-schedule-2.1.0.tgz#068ae38d7351c330616f7fe7cdb05036f977cbaf"
+ integrity sha512-nl4JTiZ7ZQDc97MmpTq9BQjYhq7gOtoh7SiPH069gBFBj0PzD8HI7zyFs6rzqL8Y5tTiEEYLxgtbx034YPrbyQ==
+ dependencies:
+ cron-parser "^3.5.0"
+ long-timeout "0.1.1"
+ sorted-array-functions "^1.3.0"
+
+nodemailer-fetch@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz#79c4908a1c0f5f375b73fe888da9828f6dc963a4"
+ integrity sha512-P7S5CEVGAmDrrpn351aXOLYs1R/7fD5NamfMCHyi6WIkbjS2eeZUB/TkuvpOQr0bvRZicVqo59+8wbhR3yrJbQ==
+
+nodemailer-shared@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz#cf5994e2fd268d00f5cf0fa767a08169edb07ec0"
+ integrity sha512-68xW5LSyPWv8R0GLm6veAvm7E+XFXkVgvE3FW0FGxNMMZqMkPFeGDVALfR1DPdSfcoO36PnW7q5AAOgFImEZGg==
+ dependencies:
+ nodemailer-fetch "1.6.0"
+
+nodemon@3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.0.2.tgz#222dd0de79fc7b7b3eedba422d2b9e5fc678621e"
+ integrity sha512-9qIN2LNTrEzpOPBaWHTm4Asy1LxXLSickZStAQ4IZe7zsoIpD/A7LWxhZV3t4Zu352uBcqVnRsDXSMR2Sc3lTA==
+ dependencies:
+ chokidar "^3.5.2"
+ debug "^4"
+ ignore-by-default "^1.0.1"
+ minimatch "^3.1.2"
+ pstree.remy "^1.1.8"
+ semver "^7.5.3"
+ simple-update-notifier "^2.0.0"
+ supports-color "^5.5.0"
+ touch "^3.1.0"
+ undefsafe "^2.0.5"
+
+noms@0.0.0:
+ version "0.0.0"
+ resolved "https://registry.yarnpkg.com/noms/-/noms-0.0.0.tgz#da8ebd9f3af9d6760919b27d9cdc8092a7332859"
+ integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==
+ dependencies:
+ inherits "^2.0.1"
+ readable-stream "~1.0.31"
+
+normalize-package-data@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+ integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+ dependencies:
+ hosted-git-info "^2.1.4"
+ resolve "^1.10.0"
+ semver "2 || 3 || 4 || 5"
+ validate-npm-package-license "^3.0.1"
+
+normalize-path@^3.0.0, normalize-path@~3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+ integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+normalize-url@^6.0.1:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
+ integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
+
+npm-bundled@^1.1.1:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1"
+ integrity sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==
+ dependencies:
+ npm-normalize-package-bin "^1.0.1"
+
+npm-normalize-package-bin@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2"
+ integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==
+
+npm-packlist@^2.1.5:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8"
+ integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==
+ dependencies:
+ glob "^7.1.6"
+ ignore-walk "^3.0.3"
+ npm-bundled "^1.1.1"
+ npm-normalize-package-bin "^1.0.1"
+
+npm-run-path@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
+ integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
+ dependencies:
+ path-key "^3.0.0"
+
+npm-run-path@^5.1.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.3.0.tgz#e23353d0ebb9317f174e93417e4a4d82d0249e9f"
+ integrity sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==
+ dependencies:
+ path-key "^4.0.0"
+
+nth-check@^2.0.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
+ integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
+ dependencies:
+ boolbase "^1.0.0"
+
+oauth-sign@^0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+ integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-assign@^4.0.1, object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
+object-copy@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+ integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ==
+ dependencies:
+ copy-descriptor "^0.1.0"
+ define-property "^0.2.5"
+ kind-of "^3.0.3"
+
+object-inspect@^1.13.1:
+ version "1.13.1"
+ resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
+ integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
+
+object-keys@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+ integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object-visit@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+ integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA==
+ dependencies:
+ isobject "^3.0.0"
+
+object.defaults@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf"
+ integrity sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==
+ dependencies:
+ array-each "^1.0.1"
+ array-slice "^1.0.0"
+ for-own "^1.0.0"
+ isobject "^3.0.0"
+
+object.map@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/object.map/-/object.map-1.0.1.tgz#cf83e59dc8fcc0ad5f4250e1f78b3b81bd801d37"
+ integrity sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==
+ dependencies:
+ for-own "^1.0.0"
+ make-iterator "^1.0.0"
+
+object.pick@^1.2.0, object.pick@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+ integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==
+ dependencies:
+ isobject "^3.0.1"
+
+oblivious-set@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
+ integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
+
+on-finished@^2.3.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
+ integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
+ dependencies:
+ ee-first "1.1.1"
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+ integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
+ dependencies:
+ wrappy "1"
+
+one-time@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/one-time/-/one-time-1.0.0.tgz#e06bc174aed214ed58edede573b433bbf827cb45"
+ integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==
+ dependencies:
+ fn.name "1.x.x"
+
+onetime@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+ integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==
+ dependencies:
+ mimic-fn "^1.0.0"
+
+onetime@^5.1.0, onetime@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
+ integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
+ dependencies:
+ mimic-fn "^2.1.0"
+
+onetime@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4"
+ integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==
+ dependencies:
+ mimic-fn "^4.0.0"
+
+only@~0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4"
+ integrity sha512-Fvw+Jemq5fjjyWz6CpKx6w9s7xxqo3+JCyM0WXWeCSOboZ8ABkyvP8ID4CZuChA/wxSx+XSJmdOm8rGVyJ1hdQ==
+
+open@8.4.0:
+ version "8.4.0"
+ resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8"
+ integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==
+ dependencies:
+ define-lazy-prop "^2.0.0"
+ is-docker "^2.1.1"
+ is-wsl "^2.2.0"
+
+open@^9.1.0:
+ version "9.1.0"
+ resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6"
+ integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==
+ dependencies:
+ default-browser "^4.0.0"
+ define-lazy-prop "^3.0.0"
+ is-inside-container "^1.0.0"
+ is-wsl "^2.2.0"
+
+opener@^1.5.2:
+ version "1.5.2"
+ resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
+ integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
+
+openpgp@^5.11.1:
+ version "5.11.2"
+ resolved "https://registry.yarnpkg.com/openpgp/-/openpgp-5.11.2.tgz#2c035a26b13feb3b0bb5180718ec91c8e65cc686"
+ integrity sha512-f8dJFVLwdkvPvW3VPFs6q9Vs2+HNhdvwls7a/MIFcQUB+XiQzRe7alfa3RtwfGJU7oUDDMAWPZ0nYsHa23Az+A==
+ dependencies:
+ asn1.js "^5.0.0"
+
+ora@5.4.1, ora@^5.4.1:
+ version "5.4.1"
+ resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18"
+ integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==
+ dependencies:
+ bl "^4.1.0"
+ chalk "^4.1.0"
+ cli-cursor "^3.1.0"
+ cli-spinners "^2.5.0"
+ is-interactive "^1.0.0"
+ is-unicode-supported "^0.1.0"
+ log-symbols "^4.1.0"
+ strip-ansi "^6.0.0"
+ wcwidth "^1.0.1"
+
+ora@^3.4.0:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/ora/-/ora-3.4.0.tgz#bf0752491059a3ef3ed4c85097531de9fdbcd318"
+ integrity sha512-eNwHudNbO1folBP3JsZ19v9azXWtQZjICdr3Q0TDPIaeBQ3mXLrh54wM+er0+hSp+dWKf+Z8KM58CYzEyIYxYg==
+ dependencies:
+ chalk "^2.4.2"
+ cli-cursor "^2.1.0"
+ cli-spinners "^2.0.0"
+ log-symbols "^2.2.0"
+ strip-ansi "^5.2.0"
+ wcwidth "^1.0.1"
+
+os-paths@^7.4.0:
+ version "7.4.0"
+ resolved "https://registry.yarnpkg.com/os-paths/-/os-paths-7.4.0.tgz#3354f1814425c232b6f42138a90e4000af6f9692"
+ integrity sha512-Ux1J4NUqC6tZayBqLN1kUlDAEvLiQlli/53sSddU4IN+h+3xxnv2HmRSMpVSvr1hvJzotfMs3ERvETGK+f4OwA==
+ optionalDependencies:
+ fsevents "*"
+
+os-tmpdir@~1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+ integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
+
+outdent@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/outdent/-/outdent-0.8.0.tgz#2ebc3e77bf49912543f1008100ff8e7f44428eb0"
+ integrity sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A==
+
+p-cancelable@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf"
+ integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==
+
+p-limit@^2.0.0, p-limit@^2.2.0:
+ version "2.3.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
+ integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
+ dependencies:
+ p-try "^2.0.0"
+
+p-limit@^3.0.2:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
+ integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
+ dependencies:
+ yocto-queue "^0.1.0"
+
+p-limit@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-5.0.0.tgz#6946d5b7140b649b7a33a027d89b4c625b3a5985"
+ integrity sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==
+ dependencies:
+ yocto-queue "^1.0.0"
+
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+ dependencies:
+ p-limit "^2.0.0"
+
+p-locate@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
+ integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
+ dependencies:
+ p-limit "^2.2.0"
+
+p-locate@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834"
+ integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==
+ dependencies:
+ p-limit "^3.0.2"
+
+p-map@4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b"
+ integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==
+ dependencies:
+ aggregate-error "^3.0.0"
+
+p-map@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d"
+ integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==
+ dependencies:
+ aggregate-error "^3.0.0"
+
+p-try@^2.0.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+ integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+package-json-from-dist@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz#e501cd3094b278495eb4258d4c9f6d5ac3019f00"
+ integrity sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==
+
+package-json@7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/package-json/-/package-json-7.0.0.tgz#1355416e50a5c1b8f1a6f471197a3650d21186bf"
+ integrity sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==
+ dependencies:
+ got "^11.8.2"
+ registry-auth-token "^4.0.0"
+ registry-url "^5.0.0"
+ semver "^7.3.5"
+
+param-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+ integrity sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==
+ dependencies:
+ no-case "^2.2.0"
+
+param-case@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
+ integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
+ dependencies:
+ dot-case "^3.0.4"
+ tslib "^2.0.3"
+
+parent-module@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+ integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+ dependencies:
+ callsites "^3.0.0"
+
+parse-filepath@^1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.2.tgz#a632127f53aaf3d15876f5872f3ffac763d6c891"
+ integrity sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==
+ dependencies:
+ is-absolute "^1.0.0"
+ map-cache "^0.2.0"
+ path-root "^0.1.1"
+
+parse-json@^5.0.0, parse-json@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
+ integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ error-ex "^1.3.1"
+ json-parse-even-better-errors "^2.3.0"
+ lines-and-columns "^1.1.6"
+
+parse-passwd@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+ integrity sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==
+
+parse-path@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-7.0.0.tgz#605a2d58d0a749c8594405d8cc3a2bf76d16099b"
+ integrity sha512-Euf9GG8WT9CdqwuWJGdf3RkUcTBArppHABkO7Lm8IzRQp0e2r/kkFnmhu4TSK30Wcu5rVAZLmfPKSBBi9tWFog==
+ dependencies:
+ protocols "^2.0.0"
+
+parse-srcset@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/parse-srcset/-/parse-srcset-1.0.2.tgz#f2bd221f6cc970a938d88556abc589caaaa2bde1"
+ integrity sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==
+
+parse-url@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-8.1.0.tgz#972e0827ed4b57fc85f0ea6b0d839f0d8a57a57d"
+ integrity sha512-xDvOoLU5XRrcOZvnI6b8zA6n9O9ejNk/GExuz1yBuWUGn9KA97GI6HTs6u02wKara1CeVmZhH+0TZFdWScR89w==
+ dependencies:
+ parse-path "^7.0.0"
+
+parseurl@^1.3.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+ integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascal-case@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e"
+ integrity sha512-qjS4s8rBOJa2Xm0jmxXiyh1+OFf6ekCWOvUaRgAQSktzlTbMotS0nmG9gyYAybCWBcuP4fsBeRCKNwGBnMe2OQ==
+ dependencies:
+ camel-case "^3.0.0"
+ upper-case-first "^1.1.0"
+
+pascal-case@^3.1.2:
+ version "3.1.2"
+ resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
+ integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
+ dependencies:
+ no-case "^3.0.4"
+ tslib "^2.0.3"
+
+pascalcase@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+ integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==
+
+passport-local@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee"
+ integrity sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==
+ dependencies:
+ passport-strategy "1.x.x"
+
+passport-strategy@1.x.x:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
+ integrity sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==
+
+passport@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/passport/-/passport-0.6.0.tgz#e869579fab465b5c0b291e841e6cc95c005fac9d"
+ integrity sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==
+ dependencies:
+ passport-strategy "1.x.x"
+ pause "0.0.1"
+ utils-merge "^1.0.1"
+
+path-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
+ integrity sha512-Ou0N05MioItesaLr9q8TtHVWmJ6fxWdqKB2RohFmNWVyJ+2zeKIeDNWAN6B/Pe7wpzWChhZX6nONYmOnMeJQ/Q==
+ dependencies:
+ no-case "^2.2.0"
+
+path-exists@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+ integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==
+
+path-exists@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
+ integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
+
+path-is-absolute@1.0.1, path-is-absolute@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+ integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
+
+path-key@^3.0.0, path-key@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
+ integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
+
+path-key@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18"
+ integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==
+
+path-parse@^1.0.7:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
+ integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
+
+path-root-regex@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
+ integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==
+
+path-root@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
+ integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==
+ dependencies:
+ path-root-regex "^0.1.0"
+
+path-scurry@^1.11.1:
+ version "1.11.1"
+ resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2"
+ integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==
+ dependencies:
+ lru-cache "^10.2.0"
+ minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
+
+path-to-regexp@^1.7.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a"
+ integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==
+ dependencies:
+ isarray "0.0.1"
+
+path-to-regexp@^6.1.0:
+ version "6.2.2"
+ resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.2.tgz#324377a83e5049cbecadc5554d6a63a9a4866b36"
+ integrity sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==
+
+path-type@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+ integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+
+pathe@^1.1.1, pathe@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.2.tgz#6c4cb47a945692e48a1ddd6e4094d170516437ec"
+ integrity sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==
+
+pathval@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
+ integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
+
+pause@0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d"
+ integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==
+
+pg-cloudflare@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98"
+ integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==
+
+pg-connection-string@2.6.1:
+ version "2.6.1"
+ resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.1.tgz#78c23c21a35dd116f48e12e23c0965e8d9e2cbfb"
+ integrity sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg==
+
+pg-connection-string@^2.6.4:
+ version "2.6.4"
+ resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.4.tgz#f543862adfa49fa4e14bc8a8892d2a84d754246d"
+ integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==
+
+pg-int8@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c"
+ integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
+
+pg-pool@^3.6.2:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.2.tgz#3a592370b8ae3f02a7c8130d245bc02fa2c5f3f2"
+ integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==
+
+pg-protocol@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.1.tgz#21333e6d83b01faaebfe7a33a7ad6bfd9ed38cb3"
+ integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==
+
+pg-types@^2.1.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3"
+ integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
+ dependencies:
+ pg-int8 "1.0.1"
+ postgres-array "~2.0.0"
+ postgres-bytea "~1.0.0"
+ postgres-date "~1.0.4"
+ postgres-interval "^1.1.0"
+
+pg@8.12.0:
+ version "8.12.0"
+ resolved "https://registry.yarnpkg.com/pg/-/pg-8.12.0.tgz#9341724db571022490b657908f65aee8db91df79"
+ integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ==
+ dependencies:
+ pg-connection-string "^2.6.4"
+ pg-pool "^3.6.2"
+ pg-protocol "^1.6.1"
+ pg-types "^2.1.0"
+ pgpass "1.x"
+ optionalDependencies:
+ pg-cloudflare "^1.1.1"
+
+pgpass@1.x:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d"
+ integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==
+ dependencies:
+ split2 "^4.1.0"
+
+picocolors@^1.0.0, picocolors@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.1.tgz#a8ad579b571952f0e5d25892de5445bcfe25aaa1"
+ integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==
+
+picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
+ integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
+
+pkg-types@^1.0.3, pkg-types@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.1.1.tgz#07b626880749beb607b0c817af63aac1845a73f2"
+ integrity sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==
+ dependencies:
+ confbox "^0.1.7"
+ mlly "^1.7.0"
+ pathe "^1.1.2"
+
+pkg-up@3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5"
+ integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==
+ dependencies:
+ find-up "^3.0.0"
+
+plop@2.7.6:
+ version "2.7.6"
+ resolved "https://registry.yarnpkg.com/plop/-/plop-2.7.6.tgz#1fa5360cd5b04e9932ce677bb6bd44750d97ae67"
+ integrity sha512-IgnYAsC3Ni7t1cDU7wH2151CD22YhMxH8PFh+iPzCf+WuGEWXslJ5t1Tpr0N/gjL23CAV/HbLAWug2IPM2YrHg==
+ dependencies:
+ "@types/liftoff" "^2.5.1"
+ chalk "^1.1.3"
+ interpret "^1.2.0"
+ liftoff "^2.5.0"
+ minimist "^1.2.5"
+ node-plop "^0.26.3"
+ ora "^3.4.0"
+ v8flags "^2.0.10"
+
+pluralize@8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1"
+ integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==
+
+pony-cause@^2.1.2:
+ version "2.1.11"
+ resolved "https://registry.yarnpkg.com/pony-cause/-/pony-cause-2.1.11.tgz#d69a20aaccdb3bdb8f74dd59e5c68d8e6772e4bd"
+ integrity sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==
+
+posix-character-classes@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+ integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg==
+
+possible-typed-array-names@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
+ integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==
+
+postcss-modules-extract-imports@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz#b4497cb85a9c0c4b5aabeb759bb25e8d89f15002"
+ integrity sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==
+
+postcss-modules-local-by-default@^4.0.5:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz#f1b9bd757a8edf4d8556e8d0f4f894260e3df78f"
+ integrity sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==
+ dependencies:
+ icss-utils "^5.0.0"
+ postcss-selector-parser "^6.0.2"
+ postcss-value-parser "^4.1.0"
+
+postcss-modules-scope@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz#a43d28289a169ce2c15c00c4e64c0858e43457d5"
+ integrity sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==
+ dependencies:
+ postcss-selector-parser "^6.0.4"
+
+postcss-modules-values@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c"
+ integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==
+ dependencies:
+ icss-utils "^5.0.0"
+
+postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz#49694cb4e7c649299fea510a29fa6577104bcf53"
+ integrity sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==
+ dependencies:
+ cssesc "^3.0.0"
+ util-deprecate "^1.0.2"
+
+postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
+ integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
+
+postcss@^8.3.11, postcss@^8.4.32, postcss@^8.4.33, postcss@^8.4.38:
+ version "8.4.38"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e"
+ integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==
+ dependencies:
+ nanoid "^3.3.7"
+ picocolors "^1.0.0"
+ source-map-js "^1.2.0"
+
+postgres-array@~2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e"
+ integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==
+
+postgres-bytea@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35"
+ integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==
+
+postgres-date@~1.0.4:
+ version "1.0.7"
+ resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8"
+ integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
+
+postgres-interval@^1.1.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695"
+ integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
+ dependencies:
+ xtend "^4.0.0"
+
+prebuild-install@^7.1.1:
+ version "7.1.2"
+ resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.2.tgz#a5fd9986f5a6251fbc47e1e5c65de71e68c0a056"
+ integrity sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ==
+ dependencies:
+ detect-libc "^2.0.0"
+ expand-template "^2.0.3"
+ github-from-package "0.0.0"
+ minimist "^1.2.3"
+ mkdirp-classic "^0.5.3"
+ napi-build-utils "^1.0.1"
+ node-abi "^3.3.0"
+ pump "^3.0.0"
+ rc "^1.2.7"
+ simple-get "^4.0.0"
+ tar-fs "^2.0.0"
+ tunnel-agent "^0.6.0"
+
+prettier-plugin-packagejson@2.4.5:
+ version "2.4.5"
+ resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.4.5.tgz#20cc396e5654b5736657bd2dfb7ac859afc618cc"
+ integrity sha512-glG71jE1gO3y5+JNAhC8X+4yrlN28rub6Aj461SKbaPie9RgMiHKcInH2Moi2VGOfkTXaEHBhg4uVMBqa+kBUA==
+ dependencies:
+ sort-package-json "2.5.1"
+ synckit "0.8.5"
+
+prettier@2.8.4:
+ version "2.8.4"
+ resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
+ integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
+
+pretty-error@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-4.0.0.tgz#90a703f46dd7234adb46d0f84823e9d1cb8f10d6"
+ integrity sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw==
+ dependencies:
+ lodash "^4.17.20"
+ renderkid "^3.0.0"
+
+pretty-format@^29.7.0:
+ version "29.7.0"
+ resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812"
+ integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==
+ dependencies:
+ "@jest/schemas" "^29.6.3"
+ ansi-styles "^5.0.0"
+ react-is "^18.0.0"
+
+process-nextick-args@~2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+ integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+progress-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/progress-stream/-/progress-stream-2.0.0.tgz#fac63a0b3d11deacbb0969abcc93b214bce19ed5"
+ integrity sha512-xJwOWR46jcXUq6EH9yYyqp+I52skPySOeHfkxOZ2IY1AiBi/sFJhbhAKHoV3OTw/omQ45KTio9215dRJ2Yxd3Q==
+ dependencies:
+ speedometer "~1.0.0"
+ through2 "~2.0.3"
+
+prompts@2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
+ integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
+ dependencies:
+ kleur "^3.0.3"
+ sisteransi "^1.0.5"
+
+prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
+property-expr@^2.0.4:
+ version "2.0.6"
+ resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.6.tgz#f77bc00d5928a6c748414ad12882e83f24aec1e8"
+ integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==
+
+proto-list@~1.2.1:
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
+ integrity sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==
+
+protocols@^2.0.0, protocols@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86"
+ integrity sha512-/XJ368cyBJ7fzLMwLKv1e4vLxOju2MNAIokcr7meSaNcVbWz/CPcW22cP04mwxOErdA5mwjA8Q6w/cdAQxVn7Q==
+
+proxy-from-env@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
+ integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
+
+pstree.remy@^1.1.8:
+ version "1.1.8"
+ resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
+ integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
+
+pump@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+ integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+ dependencies:
+ end-of-stream "^1.1.0"
+ once "^1.3.1"
+
+punycode@1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+ integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==
+
+punycode@^2.1.0:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5"
+ integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+
+purest@4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/purest/-/purest-4.0.2.tgz#6d60403f00731bbe3c508955c96d56e8c0f30098"
+ integrity sha512-Uq6kdia8zGVHOb/0zAOb7FvKFMKeyeTZTLEwpO0JR3cIFEkpH6asv3ls9M9URDjHiYIdgAPmht5ecSbvPacfyg==
+ dependencies:
+ "@simov/deep-extend" "^1.0.0"
+ qs "^6.10.3"
+ request-compose "^2.1.4"
+ request-multipart "^1.0.0"
+ request-oauth "^1.0.1"
+
+qs@6.11.1:
+ version "6.11.1"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f"
+ integrity sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==
+ dependencies:
+ side-channel "^1.0.4"
+
+qs@^6.10.3, qs@^6.11.2, qs@^6.4.0, qs@^6.5.2, qs@^6.9.6:
+ version "6.12.1"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.12.1.tgz#39422111ca7cbdb70425541cba20c7d7b216599a"
+ integrity sha512-zWmv4RSuB9r2mYQw3zxQuHWeU+42aKi1wWig/j4ele4ygELZ7PEO6MM7rim9oAQH2A5MWfsAVf/jPvTPgCbvUQ==
+ dependencies:
+ side-channel "^1.0.6"
+
+query-string@^7.1.3:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.3.tgz#a1cf90e994abb113a325804a972d98276fe02328"
+ integrity sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==
+ dependencies:
+ decode-uri-component "^0.2.2"
+ filter-obj "^1.1.0"
+ split-on-first "^1.0.0"
+ strict-uri-encode "^2.0.0"
+
+querystring@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+ integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==
+
+queue-microtask@^1.2.2:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
+ integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
+
+queue-tick@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142"
+ integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==
+
+quick-lru@^5.1.1:
+ version "5.1.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
+ integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
+
+randombytes@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+ integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+ dependencies:
+ safe-buffer "^5.1.0"
+
+range-parser@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+ integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@^2.2.0, raw-body@^2.3.3:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
+ integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
+ dependencies:
+ bytes "3.1.2"
+ http-errors "2.0.0"
+ iconv-lite "0.4.24"
+ unpipe "1.0.0"
+
+rc@1.2.8, rc@^1.2.7, rc@^1.2.8:
+ version "1.2.8"
+ resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+ integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+ dependencies:
+ deep-extend "^0.6.0"
+ ini "~1.3.0"
+ minimist "^1.2.0"
+ strip-json-comments "~2.0.1"
+
+react-dnd-html5-backend@16.0.1:
+ version "16.0.1"
+ resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-16.0.1.tgz#87faef15845d512a23b3c08d29ecfd34871688b6"
+ integrity sha512-Wu3dw5aDJmOGw8WjH1I1/yTH+vlXEL4vmjk5p+MHxP8HuHJS1lAGeIdG/hze1AvNeXWo/JgULV87LyQOr+r5jw==
+ dependencies:
+ dnd-core "^16.0.1"
+
+react-dnd@16.0.1:
+ version "16.0.1"
+ resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-16.0.1.tgz#2442a3ec67892c60d40a1559eef45498ba26fa37"
+ integrity sha512-QeoM/i73HHu2XF9aKksIUuamHPDvRglEwdHL4jsp784BgUuWcg6mzfxT0QDdQz8Wj0qyRKx2eMg8iZtWvU4E2Q==
+ dependencies:
+ "@react-dnd/invariant" "^4.0.1"
+ "@react-dnd/shallowequal" "^4.0.1"
+ dnd-core "^16.0.1"
+ fast-deep-equal "^3.1.3"
+ hoist-non-react-statics "^3.3.2"
+
+react-dom@^18.0.0:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
+ integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
+ dependencies:
+ loose-envify "^1.1.0"
+ scheduler "^0.23.2"
+
+react-error-boundary@3.1.4:
+ version "3.1.4"
+ resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-3.1.4.tgz#255db92b23197108757a888b01e5b729919abde0"
+ integrity sha512-uM9uPzZJTF6wRQORmSrvOIgt4lJ9MC1sNgEOj2XGsDTRE4kmpWxg7ENK9EWNKJRMAOY9z0MuF4yIfl6gp4sotA==
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+
+react-fast-compare@^2.0.1:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
+ integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
+
+react-fast-compare@^3.1.1:
+ version "3.2.2"
+ resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
+ integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==
+
+react-helmet@6.1.0, react-helmet@^6.1.0:
+ version "6.1.0"
+ resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-6.1.0.tgz#a750d5165cb13cf213e44747502652e794468726"
+ integrity sha512-4uMzEY9nlDlgxr61NL3XbKRy1hEkXmKNXhjbAIOVw5vcFrsdYbH2FEwcNyWvWinl103nXgzYNlns9ca+8kFiWw==
+ dependencies:
+ object-assign "^4.1.1"
+ prop-types "^15.7.2"
+ react-fast-compare "^3.1.1"
+ react-side-effect "^2.1.0"
+
+react-intl@6.4.1:
+ version "6.4.1"
+ resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.4.1.tgz#01e4bd5497cb93d87146e966d8eda25851d4d9b6"
+ integrity sha512-/aT5595AEMZ+Pjmt8W2R5/ZkYJmyyd6jTzHzqhJ1LnfeG36+N5huBtykxYhHqLc1BrIRQ1fTX1orYC0Ej5ojtg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "1.14.3"
+ "@formatjs/icu-messageformat-parser" "2.3.1"
+ "@formatjs/intl" "2.7.1"
+ "@formatjs/intl-displaynames" "6.3.1"
+ "@formatjs/intl-listformat" "7.2.1"
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/react" "16 || 17 || 18"
+ hoist-non-react-statics "^3.3.2"
+ intl-messageformat "10.3.4"
+ tslib "^2.4.0"
+
+react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
+react-is@^18.0.0, react-is@^18.2.0:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e"
+ integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==
+
+react-query@3.39.3:
+ version "3.39.3"
+ resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35"
+ integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ broadcast-channel "^3.4.1"
+ match-sorter "^6.0.2"
+
+react-redux@8.1.1:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.1.tgz#8e740f3fd864a4cd0de5ba9cdc8ad39cc9e7c81a"
+ integrity sha512-5W0QaKtEhj+3bC0Nj0NkqkhIv8gLADH/2kYFMTHxCVqQILiWzLv6MaLuV5wJU3BQEdHKzTfcvPN0WMS6SC1oyA==
+ dependencies:
+ "@babel/runtime" "^7.12.1"
+ "@types/hoist-non-react-statics" "^3.3.1"
+ "@types/use-sync-external-store" "^0.0.3"
+ hoist-non-react-statics "^3.3.2"
+ react-is "^18.0.0"
+ use-sync-external-store "^1.0.0"
+
+react-refresh@0.14.0:
+ version "0.14.0"
+ resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.0.tgz#4e02825378a5f227079554d4284889354e5f553e"
+ integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
+
+react-remove-scroll-bar@^2.3.4, react-remove-scroll-bar@^2.3.6:
+ version "2.3.6"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.6.tgz#3e585e9d163be84a010180b18721e851ac81a29c"
+ integrity sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==
+ dependencies:
+ react-style-singleton "^2.2.1"
+ tslib "^2.0.0"
+
+react-remove-scroll@2.5.7:
+ version "2.5.7"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz#15a1fd038e8497f65a695bf26a4a57970cac1ccb"
+ integrity sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==
+ dependencies:
+ react-remove-scroll-bar "^2.3.4"
+ react-style-singleton "^2.2.1"
+ tslib "^2.1.0"
+ use-callback-ref "^1.3.0"
+ use-sidecar "^1.1.2"
+
+react-remove-scroll@^2.5.9:
+ version "2.5.10"
+ resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.5.10.tgz#5fae456a23962af6d3c38ca1978bcfe0806c4061"
+ integrity sha512-m3zvBRANPBw3qxVVjEIPEQinkcwlFZ4qyomuWVpNJdv4c6MvHfXV0C3L9Jx5rr3HeBHKNRX+1jreB5QloDIJjA==
+ dependencies:
+ react-remove-scroll-bar "^2.3.6"
+ react-style-singleton "^2.2.1"
+ tslib "^2.1.0"
+ use-callback-ref "^1.3.0"
+ use-sidecar "^1.1.2"
+
+react-router-dom@5.3.4:
+ version "5.3.4"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6"
+ integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==
+ dependencies:
+ "@babel/runtime" "^7.12.13"
+ history "^4.9.0"
+ loose-envify "^1.3.1"
+ prop-types "^15.6.2"
+ react-router "5.3.4"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react-router@5.3.4:
+ version "5.3.4"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.3.4.tgz#8ca252d70fcc37841e31473c7a151cf777887bb5"
+ integrity sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==
+ dependencies:
+ "@babel/runtime" "^7.12.13"
+ history "^4.9.0"
+ hoist-non-react-statics "^3.1.0"
+ loose-envify "^1.3.1"
+ path-to-regexp "^1.7.0"
+ prop-types "^15.6.2"
+ react-is "^16.6.0"
+ tiny-invariant "^1.0.2"
+ tiny-warning "^1.0.0"
+
+react-select@5.7.0:
+ version "5.7.0"
+ resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.0.tgz#82921b38f1fcf1471a0b62304da01f2896cd8ce6"
+ integrity sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==
+ dependencies:
+ "@babel/runtime" "^7.12.0"
+ "@emotion/cache" "^11.4.0"
+ "@emotion/react" "^11.8.1"
+ "@floating-ui/dom" "^1.0.1"
+ "@types/react-transition-group" "^4.4.0"
+ memoize-one "^6.0.0"
+ prop-types "^15.6.0"
+ react-transition-group "^4.3.0"
+ use-isomorphic-layout-effect "^1.1.2"
+
+react-side-effect@^2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/react-side-effect/-/react-side-effect-2.1.2.tgz#dc6345b9e8f9906dc2eeb68700b615e0b4fe752a"
+ integrity sha512-PVjOcvVOyIILrYoyGEpDN3vmYNLdy1CajSFNt4TDsVQC5KpTijDvWVoR+/7Rz2xT978D8/ZtFceXxzsPwZEDvw==
+
+react-style-singleton@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.1.tgz#f99e420492b2d8f34d38308ff660b60d0b1205b4"
+ integrity sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==
+ dependencies:
+ get-nonce "^1.0.0"
+ invariant "^2.2.4"
+ tslib "^2.0.0"
+
+react-transition-group@^4.3.0:
+ version "4.4.5"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
+ integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ dom-helpers "^5.0.1"
+ loose-envify "^1.4.0"
+ prop-types "^15.6.2"
+
+react-window@1.8.8:
+ version "1.8.8"
+ resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.8.tgz#1b52919f009ddf91970cbdb2050a6c7be44df243"
+ integrity sha512-D4IiBeRtGXziZ1n0XklnFGu7h9gU684zepqyKzgPNzrsrk7xOCxni+TCckjg2Nr/DiaEEGVVmnhYSlT2rB47dQ==
+ dependencies:
+ "@babel/runtime" "^7.0.0"
+ memoize-one ">=3.1.1 <6"
+
+react@^18.0.0:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
+ integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
+ dependencies:
+ loose-envify "^1.1.0"
+
+read-pkg-up@7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+ integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
+ dependencies:
+ find-up "^4.1.0"
+ read-pkg "^5.2.0"
+ type-fest "^0.8.1"
+
+read-pkg@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^2.5.0"
+ parse-json "^5.0.0"
+ type-fest "^0.6.0"
+
+readable-stream@3, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
+ version "3.6.2"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967"
+ integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==
+ dependencies:
+ inherits "^2.0.3"
+ string_decoder "^1.1.1"
+ util-deprecate "^1.0.1"
+
+readable-stream@~1.0.31:
+ version "1.0.34"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c"
+ integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.1"
+ isarray "0.0.1"
+ string_decoder "~0.10.x"
+
+readable-stream@~2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
+ integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
+ dependencies:
+ core-util-is "~1.0.0"
+ inherits "~2.0.3"
+ isarray "~1.0.0"
+ process-nextick-args "~2.0.0"
+ safe-buffer "~5.1.1"
+ string_decoder "~1.1.1"
+ util-deprecate "~1.0.1"
+
+readdirp@~3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
+ integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
+ dependencies:
+ picomatch "^2.2.1"
+
+rechoir@^0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
+ integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
+ dependencies:
+ resolve "^1.1.6"
+
+rechoir@^0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22"
+ integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==
+ dependencies:
+ resolve "^1.20.0"
+
+redux-thunk@^2.4.2:
+ version "2.4.2"
+ resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b"
+ integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==
+
+redux@^4.2.0, redux@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
+ integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
+ dependencies:
+ "@babel/runtime" "^7.9.2"
+
+regenerator-runtime@^0.14.0:
+ version "0.14.1"
+ resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
+ integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+ integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+ dependencies:
+ extend-shallow "^3.0.2"
+ safe-regex "^1.1.0"
+
+registry-auth-token@^4.0.0:
+ version "4.2.2"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.2.tgz#f02d49c3668884612ca031419491a13539e21fac"
+ integrity sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==
+ dependencies:
+ rc "1.2.8"
+
+registry-auth-token@^5.0.2:
+ version "5.0.2"
+ resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-5.0.2.tgz#8b026cc507c8552ebbe06724136267e63302f756"
+ integrity sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==
+ dependencies:
+ "@pnpm/npm-conf" "^2.1.0"
+
+registry-url@^5.0.0, registry-url@^5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
+ integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
+ dependencies:
+ rc "^1.2.8"
+
+relateurl@^0.2.7:
+ version "0.2.7"
+ resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+ integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
+
+remove-accents@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687"
+ integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==
+
+renderkid@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-3.0.0.tgz#5fd823e4d6951d37358ecc9a58b1f06836b6268a"
+ integrity sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg==
+ dependencies:
+ css-select "^4.1.3"
+ dom-converter "^0.2.0"
+ htmlparser2 "^6.1.0"
+ lodash "^4.17.21"
+ strip-ansi "^6.0.1"
+
+request-compose@^2.1.4, request-compose@^2.1.6:
+ version "2.1.6"
+ resolved "https://registry.yarnpkg.com/request-compose/-/request-compose-2.1.6.tgz#f498d6afd4ce983066432446d4b1e3d3d51fbd0f"
+ integrity sha512-S07L+2VbJB32WddD/o/PnYGKym63zLVbymygVWXvt8L79VAngcjAxhHaGuFOICLxEV90EasEPzqPKKHPspXP8w==
+
+request-ip@3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611"
+ integrity sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA==
+
+request-multipart@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/request-multipart/-/request-multipart-1.0.0.tgz#26fe57634e379a5686eb499788ecd8b4fd51deaf"
+ integrity sha512-dazx88T19dIKFNc0XdlZV8H46D2RmNFdR4mipcbrFOaN70PSSSMM3urVY+eVbrpraf/fHXccxFhLvG1wkSUtKQ==
+ dependencies:
+ bl "^4.0.3"
+ isstream "^0.1.2"
+ mime-types "^2.1.28"
+ multistream "^4.0.1"
+ uuid "^8.3.2"
+
+request-oauth@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/request-oauth/-/request-oauth-1.0.1.tgz#dedb0c4a37234d9e93f377ddb0aaab425f31239e"
+ integrity sha512-85THTg1RgOYtqQw42JON6AqvHLptlj1biw265Tsq4fD4cPdUvhDB2Qh9NTv17yCD322ROuO9aOmpc4GyayGVBA==
+ dependencies:
+ oauth-sign "^0.9.0"
+ qs "^6.9.6"
+ uuid "^8.3.2"
+
+require-directory@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+ integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==
+
+require-from-string@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
+ integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==
+
+reselect@^4.1.8:
+ version "4.1.8"
+ resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524"
+ integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==
+
+resolve-alpn@^1.0.0:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-alpn/-/resolve-alpn-1.2.1.tgz#b7adbdac3546aaaec20b45e7d8265927072726f9"
+ integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==
+
+resolve-cwd@3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
+ integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
+ dependencies:
+ resolve-from "^5.0.0"
+
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+ integrity sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==
+ dependencies:
+ expand-tilde "^2.0.0"
+ global-modules "^1.0.0"
+
+resolve-from@5.0.0, resolve-from@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
+ integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
+
+resolve-from@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+ integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-path@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.4.0.tgz#c4bda9f5efb2fce65247873ab36bb4d834fe16f7"
+ integrity sha512-i1xevIst/Qa+nA9olDxLWnLk8YZbi8R/7JPbCMcgyWaFR6bKWaexgJgEB5oc2PKMjYdrHynyz0NY+if+H98t1w==
+ dependencies:
+ http-errors "~1.6.2"
+ path-is-absolute "1.0.1"
+
+resolve-pathname@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
+ integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
+
+resolve-url@^0.2.1:
+ version "0.2.1"
+ resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+ integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg==
+
+resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.19.0, resolve@^1.20.0, resolve@~1.22.1:
+ version "1.22.8"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
+ integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
+ dependencies:
+ is-core-module "^2.13.0"
+ path-parse "^1.0.7"
+ supports-preserve-symlinks-flag "^1.0.0"
+
+responselike@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/responselike/-/responselike-2.0.1.tgz#9a0bc8fdc252f3fb1cca68b016591059ba1422bc"
+ integrity sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==
+ dependencies:
+ lowercase-keys "^2.0.0"
+
+restore-cursor@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+ integrity sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==
+ dependencies:
+ onetime "^2.0.0"
+ signal-exit "^3.0.2"
+
+restore-cursor@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e"
+ integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==
+ dependencies:
+ onetime "^5.1.0"
+ signal-exit "^3.0.2"
+
+ret@~0.1.10:
+ version "0.1.15"
+ resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+ integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+reusify@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
+rimraf@3.0.2, rimraf@^3.0.0:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
+ integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
+ dependencies:
+ glob "^7.1.3"
+
+rimraf@^2.6.3:
+ version "2.7.1"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
+ integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
+ dependencies:
+ glob "^7.1.3"
+
+rimraf@^5.0.5:
+ version "5.0.7"
+ resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.7.tgz#27bddf202e7d89cb2e0381656380d1734a854a74"
+ integrity sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==
+ dependencies:
+ glob "^10.3.7"
+
+rollup@^4.13.0, rollup@^4.2.0:
+ version "4.18.0"
+ resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.18.0.tgz#497f60f0c5308e4602cf41136339fbf87d5f5dda"
+ integrity sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==
+ dependencies:
+ "@types/estree" "1.0.5"
+ optionalDependencies:
+ "@rollup/rollup-android-arm-eabi" "4.18.0"
+ "@rollup/rollup-android-arm64" "4.18.0"
+ "@rollup/rollup-darwin-arm64" "4.18.0"
+ "@rollup/rollup-darwin-x64" "4.18.0"
+ "@rollup/rollup-linux-arm-gnueabihf" "4.18.0"
+ "@rollup/rollup-linux-arm-musleabihf" "4.18.0"
+ "@rollup/rollup-linux-arm64-gnu" "4.18.0"
+ "@rollup/rollup-linux-arm64-musl" "4.18.0"
+ "@rollup/rollup-linux-powerpc64le-gnu" "4.18.0"
+ "@rollup/rollup-linux-riscv64-gnu" "4.18.0"
+ "@rollup/rollup-linux-s390x-gnu" "4.18.0"
+ "@rollup/rollup-linux-x64-gnu" "4.18.0"
+ "@rollup/rollup-linux-x64-musl" "4.18.0"
+ "@rollup/rollup-win32-arm64-msvc" "4.18.0"
+ "@rollup/rollup-win32-ia32-msvc" "4.18.0"
+ "@rollup/rollup-win32-x64-msvc" "4.18.0"
+ fsevents "~2.3.2"
+
+run-applescript@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c"
+ integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==
+ dependencies:
+ execa "^5.0.0"
+
+run-async@^2.4.0:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455"
+ integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==
+
+run-parallel@^1.1.9:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
+ integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
+ dependencies:
+ queue-microtask "^1.2.2"
+
+rxjs@7.8.1, rxjs@^7.5.5, rxjs@^7.8.1:
+ version "7.8.1"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543"
+ integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==
+ dependencies:
+ tslib "^2.1.0"
+
+rxjs@^6.4.0, rxjs@^6.6.0:
+ version "6.6.7"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
+ integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
+ dependencies:
+ tslib "^1.9.0"
+
+safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0:
+ version "5.2.1"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
+ integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
+
+safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+ integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-regex@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+ integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg==
+ dependencies:
+ ret "~0.1.10"
+
+safe-stable-stringify@^2.3.1:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886"
+ integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+sanitize-html@2.13.0:
+ version "2.13.0"
+ resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-2.13.0.tgz#71aedcdb777897985a4ea1877bf4f895a1170dae"
+ integrity sha512-Xff91Z+4Mz5QiNSLdLWwjgBDm5b1RU6xBT0+12rapjiaR7SwfRdjw8f+6Rir2MXKLrDicRFHdb51hGOAxmsUIA==
+ dependencies:
+ deepmerge "^4.2.2"
+ escape-string-regexp "^4.0.0"
+ htmlparser2 "^8.0.0"
+ is-plain-object "^5.0.0"
+ parse-srcset "^1.0.2"
+ postcss "^8.3.11"
+
+sax@1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
+ integrity sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==
+
+sax@>=0.6.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f"
+ integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==
+
+scheduler@^0.23.2:
+ version "0.23.2"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
+ integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
+ dependencies:
+ loose-envify "^1.1.0"
+
+schema-utils@^3.0.0, schema-utils@^3.1.1, schema-utils@^3.2.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe"
+ integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ ajv "^6.12.5"
+ ajv-keywords "^3.5.2"
+
+schema-utils@^4.0.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.2.0.tgz#70d7c93e153a273a805801882ebd3bff20d89c8b"
+ integrity sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==
+ dependencies:
+ "@types/json-schema" "^7.0.9"
+ ajv "^8.9.0"
+ ajv-formats "^2.1.1"
+ ajv-keywords "^5.1.0"
+
+scroll-into-view-if-needed@^2.2.20:
+ version "2.2.31"
+ resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.31.tgz#d3c482959dc483e37962d1521254e3295d0d1587"
+ integrity sha512-dGCXy99wZQivjmjIqihaBQNjryrz5rueJY7eHfTdyWEiR4ttYpsajb14rn9s5d4DY4EcY6+4+U/maARBXJedkA==
+ dependencies:
+ compute-scroll-into-view "^1.0.20"
+
+secp256k1@^4.0.3:
+ version "4.0.3"
+ resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303"
+ integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==
+ dependencies:
+ elliptic "^6.5.4"
+ node-addon-api "^2.0.0"
+ node-gyp-build "^4.2.0"
+
+"semver@2 || 3 || 4 || 5":
+ version "5.7.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8"
+ integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==
+
+semver@7.5.4, semver@~7.5.4:
+ version "7.5.4"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
+ integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
+ dependencies:
+ lru-cache "^6.0.0"
+
+semver@^6.0.0:
+ version "6.3.1"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
+ integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
+
+semver@^7.3.5, semver@^7.3.8, semver@^7.5.3, semver@^7.5.4:
+ version "7.6.2"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.2.tgz#1e3b34759f896e8f14d6134732ce798aeb0c6e13"
+ integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==
+
+sendmail@^1.6.1:
+ version "1.6.1"
+ resolved "https://registry.yarnpkg.com/sendmail/-/sendmail-1.6.1.tgz#6be92fb4be70d1d9ad102030aeb1e737bd512159"
+ integrity sha512-lIhvnjSi5e5jL8wA1GPP6j2QVlx6JOEfmdn0QIfmuJdmXYGmJ375kcOU0NSm/34J+nypm4sa1AXrYE5w3uNIIA==
+ dependencies:
+ dkim-signer "0.2.2"
+ mailcomposer "3.12.0"
+
+sentence-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-2.1.1.tgz#1f6e2dda39c168bf92d13f86d4a918933f667ed4"
+ integrity sha512-ENl7cYHaK/Ktwk5OTD+aDbQ3uC8IByu/6Bkg+HDv8Mm+XnBnppVNalcfJTNsp1ibstKh030/JKQQWglDvtKwEQ==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case-first "^1.1.2"
+
+serialize-javascript@^6.0.1:
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2"
+ integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==
+ dependencies:
+ randombytes "^2.1.0"
+
+set-function-length@^1.2.1:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
+ integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
+ dependencies:
+ define-data-property "^1.1.4"
+ es-errors "^1.3.0"
+ function-bind "^1.1.2"
+ get-intrinsic "^1.2.4"
+ gopd "^1.0.1"
+ has-property-descriptors "^1.0.2"
+
+set-value@^2.0.0, set-value@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+ integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
+ dependencies:
+ extend-shallow "^2.0.1"
+ is-extendable "^0.1.1"
+ is-plain-object "^2.0.3"
+ split-string "^3.0.1"
+
+setprototypeof@1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+ integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+setprototypeof@1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
+ integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
+
+shallowequal@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
+ integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
+
+sharp@0.32.6:
+ version "0.32.6"
+ resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.6.tgz#6ad30c0b7cd910df65d5f355f774aa4fce45732a"
+ integrity sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==
+ dependencies:
+ color "^4.2.3"
+ detect-libc "^2.0.2"
+ node-addon-api "^6.1.0"
+ prebuild-install "^7.1.1"
+ semver "^7.5.4"
+ simple-get "^4.0.1"
+ tar-fs "^3.0.4"
+ tunnel-agent "^0.6.0"
+
+shebang-command@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
+ integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
+ dependencies:
+ shebang-regex "^3.0.0"
+
+shebang-regex@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
+ integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
+
+shell-quote@^1.8.1:
+ version "1.8.1"
+ resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
+ integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
+
+side-channel@^1.0.4, side-channel@^1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
+ integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
+ dependencies:
+ call-bind "^1.0.7"
+ es-errors "^1.3.0"
+ get-intrinsic "^1.2.4"
+ object-inspect "^1.13.1"
+
+sift@16.0.1:
+ version "16.0.1"
+ resolved "https://registry.yarnpkg.com/sift/-/sift-16.0.1.tgz#e9c2ccc72191585008cf3e36fc447b2d2633a053"
+ integrity sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==
+
+siginfo@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30"
+ integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==
+
+signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
+ version "3.0.7"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
+ integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
+
+signal-exit@^4.0.1, signal-exit@^4.1.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
+ integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
+
+simple-concat@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f"
+ integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==
+
+simple-get@^4.0.0, simple-get@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543"
+ integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==
+ dependencies:
+ decompress-response "^6.0.0"
+ once "^1.3.1"
+ simple-concat "^1.0.0"
+
+simple-swizzle@^0.2.2:
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
+ integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
+ dependencies:
+ is-arrayish "^0.3.1"
+
+simple-update-notifier@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz#d70b92bdab7d6d90dfd73931195a30b6e3d7cebb"
+ integrity sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==
+ dependencies:
+ semver "^7.5.3"
+
+sirv@^2.0.3:
+ version "2.0.4"
+ resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0"
+ integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==
+ dependencies:
+ "@polka/url" "^1.0.0-next.24"
+ mrmime "^2.0.0"
+ totalist "^3.0.0"
+
+sisteransi@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
+ integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
+
+slash@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
+ integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
+
+slash@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7"
+ integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==
+
+slate-history@0.93.0:
+ version "0.93.0"
+ resolved "https://registry.yarnpkg.com/slate-history/-/slate-history-0.93.0.tgz#d2fad47e4e8b262ab7c86b653f5dd6d9b6d85277"
+ integrity sha512-Gr1GMGPipRuxIz41jD2/rbvzPj8eyar56TVMyJBvBeIpQSSjNISssvGNDYfJlSWM8eaRqf6DAcxMKzsLCYeX6g==
+ dependencies:
+ is-plain-object "^5.0.0"
+
+slate-react@0.98.3:
+ version "0.98.3"
+ resolved "https://registry.yarnpkg.com/slate-react/-/slate-react-0.98.3.tgz#5090d269d69186f3ec2a6b5862d2645f01772eda"
+ integrity sha512-p1BnF9eRyRM0i5hkgOb11KgmpWLQm9Zyp6jVkOAj5fPdIGheKhg48Z7aWKrayeJ4nmRyi/NjRZz/io5hQcphmw==
+ dependencies:
+ "@juggle/resize-observer" "^3.4.0"
+ "@types/is-hotkey" "^0.1.1"
+ "@types/lodash" "^4.14.149"
+ direction "^1.0.3"
+ is-hotkey "^0.1.6"
+ is-plain-object "^5.0.0"
+ lodash "^4.17.4"
+ scroll-into-view-if-needed "^2.2.20"
+ tiny-invariant "1.0.6"
+
+slate@0.94.1:
+ version "0.94.1"
+ resolved "https://registry.yarnpkg.com/slate/-/slate-0.94.1.tgz#13b0ba7d0a7eeb0ec89a87598e9111cbbd685696"
+ integrity sha512-GH/yizXr1ceBoZ9P9uebIaHe3dC/g6Plpf9nlUwnvoyf6V1UOYrRwkabtOCd3ZfIGxomY4P7lfgLr7FPH8/BKA==
+ dependencies:
+ immer "^9.0.6"
+ is-plain-object "^5.0.0"
+ tiny-warning "^1.0.3"
+
+snake-case@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
+ integrity sha512-FMR5YoPFwOLuh4rRz92dywJjyKYZNLpMn1R5ujVpIYkbA9p01fq8RMg0FkO4M+Yobt4MjHeLTJVm5xFFBHSV2Q==
+ dependencies:
+ no-case "^2.2.0"
+
+snapdragon@^0.8.1:
+ version "0.8.2"
+ resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+ integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+ dependencies:
+ base "^0.11.1"
+ debug "^2.2.0"
+ define-property "^0.2.5"
+ extend-shallow "^2.0.1"
+ map-cache "^0.2.2"
+ source-map "^0.5.6"
+ source-map-resolve "^0.5.0"
+ use "^3.1.0"
+
+sort-object-keys@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
+ integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
+
+sort-package-json@2.5.1:
+ version "2.5.1"
+ resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-2.5.1.tgz#5c0f2ce8cc8851988e5039f76b8978439439039d"
+ integrity sha512-vx/KoZxm8YNMUqdlw7SGTfqR5pqZ/sUfgOuRtDILiOy/3AvzhAibyUe2cY3OpLs3oRSow9up4yLVtQaM24rbDQ==
+ dependencies:
+ detect-indent "^7.0.1"
+ detect-newline "^4.0.0"
+ get-stdin "^9.0.0"
+ git-hooks-list "^3.0.0"
+ globby "^13.1.2"
+ is-plain-obj "^4.1.0"
+ sort-object-keys "^1.1.3"
+
+sorted-array-functions@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/sorted-array-functions/-/sorted-array-functions-1.3.0.tgz#8605695563294dffb2c9796d602bd8459f7a0dd5"
+ integrity sha512-2sqgzeFlid6N4Z2fUQ1cvFmTOLRi/sEDzSQ0OKYchqgoPmQBVyM3959qYx3fpS6Esef80KjmpgPeEr028dP3OA==
+
+source-list-map@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+ integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
+
+source-map-js@^1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"
+ integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==
+
+source-map-resolve@^0.5.0:
+ version "0.5.3"
+ resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a"
+ integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==
+ dependencies:
+ atob "^2.1.2"
+ decode-uri-component "^0.2.0"
+ resolve-url "^0.2.1"
+ source-map-url "^0.4.0"
+ urix "^0.1.0"
+
+source-map-support@~0.5.20:
+ version "0.5.21"
+ resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
+ integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
+ dependencies:
+ buffer-from "^1.0.0"
+ source-map "^0.6.0"
+
+source-map-url@^0.4.0:
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56"
+ integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==
+
+source-map@^0.5.6, source-map@^0.5.7:
+ version "0.5.7"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+ integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
+
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+ integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+source-map@^0.7.3:
+ version "0.7.4"
+ resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656"
+ integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==
+
+spawn-command@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e"
+ integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==
+
+spdx-correct@^3.0.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.2.0.tgz#4f5ab0668f0059e34f9c00dce331784a12de4e9c"
+ integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==
+ dependencies:
+ spdx-expression-parse "^3.0.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz#5d607d27fc806f66d7b64a766650fa890f04ed66"
+ integrity sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==
+
+spdx-expression-parse@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679"
+ integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==
+ dependencies:
+ spdx-exceptions "^2.1.0"
+ spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+ version "3.0.18"
+ resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz#22aa922dcf2f2885a6494a261f2d8b75345d0326"
+ integrity sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==
+
+speedometer@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/speedometer/-/speedometer-1.0.0.tgz#cd671cb06752c22bca3370e2f334440be4fc62e2"
+ integrity sha512-lgxErLl/7A5+vgIIXsh9MbeukOaCb2axgQ+bKCdIE+ibNT4XNYGNCR1qFEGq6F+YDASXK3Fh/c5FgtZchFolxw==
+
+split-on-first@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
+ integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
+
+split-string@^3.0.1:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+ integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+ dependencies:
+ extend-shallow "^3.0.0"
+
+split2@^4.1.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4"
+ integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==
+
+sprintf-js@~1.0.2:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+ integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==
+
+stack-trace@0.0.x:
+ version "0.0.10"
+ resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
+ integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==
+
+stackback@0.0.2:
+ version "0.0.2"
+ resolved "https://registry.yarnpkg.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b"
+ integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==
+
+stackframe@^1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310"
+ integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==
+
+static-extend@^0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+ integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==
+ dependencies:
+ define-property "^0.2.5"
+ object-copy "^0.1.0"
+
+statuses@2.0.1, statuses@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
+ integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
+
+"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@^1.5.0:
+ version "1.5.0"
+ resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+ integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
+
+std-env@^3.5.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/std-env/-/std-env-3.7.0.tgz#c9f7386ced6ecf13360b6c6c55b8aaa4ef7481d2"
+ integrity sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==
+
+stream-chain@2.2.5, stream-chain@^2.2.5:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/stream-chain/-/stream-chain-2.2.5.tgz#b30967e8f14ee033c5b9a19bbe8a2cba90ba0d09"
+ integrity sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==
+
+stream-json@1.8.0:
+ version "1.8.0"
+ resolved "https://registry.yarnpkg.com/stream-json/-/stream-json-1.8.0.tgz#53f486b2e3b4496c506131f8d7260ba42def151c"
+ integrity sha512-HZfXngYHUAr1exT4fxlbc1IOce1RYxp2ldeaf97LYCOPSoOqY/1Psp7iGvpb+6JIOgkra9zDYnPX01hGAHzEPw==
+ dependencies:
+ stream-chain "^2.2.5"
+
+stream-slice@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/stream-slice/-/stream-slice-0.1.2.tgz#2dc4f4e1b936fb13f3eb39a2def1932798d07a4b"
+ integrity sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA==
+
+streamx@^2.15.0, streamx@^2.18.0:
+ version "2.18.0"
+ resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.18.0.tgz#5bc1a51eb412a667ebfdcd4e6cf6a6fc65721ac7"
+ integrity sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==
+ dependencies:
+ fast-fifo "^1.3.2"
+ queue-tick "^1.0.1"
+ text-decoder "^1.1.0"
+ optionalDependencies:
+ bare-events "^2.2.0"
+
+strict-uri-encode@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
+ integrity sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==
+
+string-argv@~0.3.1:
+ version "0.3.2"
+ resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6"
+ integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==
+
+"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
+ integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
+ dependencies:
+ emoji-regex "^8.0.0"
+ is-fullwidth-code-point "^3.0.0"
+ strip-ansi "^6.0.1"
+
+string-width@^5.0.1, string-width@^5.1.2:
+ version "5.1.2"
+ resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
+ integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
+ dependencies:
+ eastasianwidth "^0.2.0"
+ emoji-regex "^9.2.2"
+ strip-ansi "^7.0.1"
+
+string_decoder@^1.1.1:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
+ integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
+ dependencies:
+ safe-buffer "~5.2.0"
+
+string_decoder@~0.10.x:
+ version "0.10.31"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
+ integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==
+
+string_decoder@~1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+ integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+ dependencies:
+ safe-buffer "~5.1.0"
+
+"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
+ integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
+ dependencies:
+ ansi-regex "^5.0.1"
+
+strip-ansi@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf"
+ integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==
+ dependencies:
+ ansi-regex "^2.0.0"
+
+strip-ansi@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+ integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+ dependencies:
+ ansi-regex "^4.1.0"
+
+strip-ansi@^7.0.1:
+ version "7.1.0"
+ resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45"
+ integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==
+ dependencies:
+ ansi-regex "^6.0.1"
+
+strip-final-newline@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
+ integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
+
+strip-final-newline@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd"
+ integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==
+
+strip-json-comments@~2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+ integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==
+
+strip-literal@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/strip-literal/-/strip-literal-2.1.0.tgz#6d82ade5e2e74f5c7e8739b6c84692bd65f0bd2a"
+ integrity sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==
+ dependencies:
+ js-tokens "^9.0.0"
+
+strnum@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db"
+ integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==
+
+style-loader@3.3.4:
+ version "3.3.4"
+ resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.4.tgz#f30f786c36db03a45cbd55b6a70d930c479090e7"
+ integrity sha512-0WqXzrsMTyb8yjZJHDqwmnwRJvhALK9LfRtRc6B4UTWe8AijYLZYZ9thuJTZc2VfQWINADW/j+LiJnfy2RoC1w==
+
+style-mod@^4.0.0, style-mod@^4.1.0:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/style-mod/-/style-mod-4.1.2.tgz#ca238a1ad4786520f7515a8539d5a63691d7bf67"
+ integrity sha512-wnD1HyVqpJUI2+eKZ+eo1UwghftP6yuFheBqqe+bWCotBjC2K1YnteJILRMs3SM4V/0dLEW1SC27MWP5y+mwmw==
+
+styled-components@5.3.3:
+ version "5.3.3"
+ resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-5.3.3.tgz#312a3d9a549f4708f0fb0edc829eb34bde032743"
+ integrity sha512-++4iHwBM7ZN+x6DtPPWkCI4vdtwumQ+inA/DdAsqYd4SVgUKJie5vXyzotA00ttcFdQkCng7zc6grwlfIfw+lw==
+ dependencies:
+ "@babel/helper-module-imports" "^7.0.0"
+ "@babel/traverse" "^7.4.5"
+ "@emotion/is-prop-valid" "^0.8.8"
+ "@emotion/stylis" "^0.8.4"
+ "@emotion/unitless" "^0.7.4"
+ babel-plugin-styled-components ">= 1.12.0"
+ css-to-react-native "^3.0.0"
+ hoist-non-react-statics "^3.0.0"
+ shallowequal "^1.1.0"
+ supports-color "^5.5.0"
+
+stylis@4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
+ integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
+
+supports-color@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+ integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==
+
+supports-color@^5.3.0, supports-color@^5.5.0:
+ version "5.5.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+ integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+ dependencies:
+ has-flag "^3.0.0"
+
+supports-color@^7.1.0:
+ version "7.2.0"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+ integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-color@^8.0.0, supports-color@^8.1.1, supports-color@~8.1.1:
+ version "8.1.1"
+ resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c"
+ integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==
+ dependencies:
+ has-flag "^4.0.0"
+
+supports-preserve-symlinks-flag@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
+ integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
+
+swap-case@^1.1.0:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3"
+ integrity sha512-BAmWG6/bx8syfc6qXPprof3Mn5vQgf5dwdUNJhsNqU9WdPt5P+ES/wQ5bxfijy8zwZgZZHslC3iAsxsuQMCzJQ==
+ dependencies:
+ lower-case "^1.1.1"
+ upper-case "^1.1.1"
+
+synckit@0.8.5:
+ version "0.8.5"
+ resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3"
+ integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==
+ dependencies:
+ "@pkgr/utils" "^2.3.1"
+ tslib "^2.5.0"
+
+tapable@^2.0.0, tapable@^2.1.1, tapable@^2.2.0, tapable@^2.2.1:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0"
+ integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
+tar-fs@^2.0.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
+ integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
+ dependencies:
+ chownr "^1.1.1"
+ mkdirp-classic "^0.5.2"
+ pump "^3.0.0"
+ tar-stream "^2.1.4"
+
+tar-fs@^3.0.4:
+ version "3.0.6"
+ resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-3.0.6.tgz#eaccd3a67d5672f09ca8e8f9c3d2b89fa173f217"
+ integrity sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==
+ dependencies:
+ pump "^3.0.0"
+ tar-stream "^3.1.5"
+ optionalDependencies:
+ bare-fs "^2.1.1"
+ bare-path "^2.1.0"
+
+tar-stream@2.2.0, tar-stream@^2.1.4:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287"
+ integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==
+ dependencies:
+ bl "^4.0.3"
+ end-of-stream "^1.4.1"
+ fs-constants "^1.0.0"
+ inherits "^2.0.3"
+ readable-stream "^3.1.1"
+
+tar-stream@^3.1.5:
+ version "3.1.7"
+ resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b"
+ integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==
+ dependencies:
+ b4a "^1.6.4"
+ fast-fifo "^1.2.0"
+ streamx "^2.15.0"
+
+tar@6.1.13, tar@^6.2.1:
+ version "6.2.1"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a"
+ integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==
+ dependencies:
+ chownr "^2.0.0"
+ fs-minipass "^2.0.0"
+ minipass "^5.0.0"
+ minizlib "^2.1.1"
+ mkdirp "^1.0.3"
+ yallist "^4.0.0"
+
+tar@^7.4.0:
+ version "7.4.0"
+ resolved "https://registry.yarnpkg.com/tar/-/tar-7.4.0.tgz#e513afef5ba20ce250fd99397b4599db07d06443"
+ integrity sha512-XQs0S8fuAkQWuqhDeCdMlJXDX80D7EOVLDPVFkna9yQfzS+PHKgfxcei0jf6/+QAWcjqrnC8uM3fSAnrQl+XYg==
+ dependencies:
+ "@isaacs/fs-minipass" "^4.0.0"
+ chownr "^3.0.0"
+ minipass "^7.1.2"
+ minizlib "^3.0.1"
+ mkdirp "^3.0.1"
+ yallist "^5.0.0"
+
+tarn@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/tarn/-/tarn-3.0.2.tgz#73b6140fbb881b71559c4f8bfde3d9a4b3d27693"
+ integrity sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==
+
+terser-webpack-plugin@^5.3.10:
+ version "5.3.10"
+ resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199"
+ integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==
+ dependencies:
+ "@jridgewell/trace-mapping" "^0.3.20"
+ jest-worker "^27.4.5"
+ schema-utils "^3.1.1"
+ serialize-javascript "^6.0.1"
+ terser "^5.26.0"
+
+terser@^5.10.0, terser@^5.26.0:
+ version "5.31.1"
+ resolved "https://registry.yarnpkg.com/terser/-/terser-5.31.1.tgz#735de3c987dd671e95190e6b98cfe2f07f3cf0d4"
+ integrity sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==
+ dependencies:
+ "@jridgewell/source-map" "^0.3.3"
+ acorn "^8.8.2"
+ commander "^2.20.0"
+ source-map-support "~0.5.20"
+
+text-decoder@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.1.0.tgz#3379e728fcf4d3893ec1aea35e8c2cac215ef190"
+ integrity sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==
+ dependencies:
+ b4a "^1.6.4"
+
+text-hex@1.0.x:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5"
+ integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==
+
+thenify-all@^1.0.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726"
+ integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==
+ dependencies:
+ thenify ">= 3.1.0 < 4"
+
+"thenify@>= 3.1.0 < 4":
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f"
+ integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==
+ dependencies:
+ any-promise "^1.0.0"
+
+through2@^2.0.1, through2@~2.0.3:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+ integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+ dependencies:
+ readable-stream "~2.3.6"
+ xtend "~4.0.1"
+
+through2@^4.0.2:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764"
+ integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==
+ dependencies:
+ readable-stream "3"
+
+through@^2.3.6:
+ version "2.3.8"
+ resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+ integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
+
+tildify@2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/tildify/-/tildify-2.0.0.tgz#f205f3674d677ce698b7067a99e949ce03b4754a"
+ integrity sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==
+
+tiny-invariant@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.0.6.tgz#b3f9b38835e36a41c843a3b0907a5a7b3755de73"
+ integrity sha512-FOyLWWVjG+aC0UqG76V53yAWdXfH8bO6FNmyZOuUrzDzK8DI3/JRY25UD7+g49JWM1LXwymsKERB+DzI0dTEQA==
+
+tiny-invariant@^1.0.2:
+ version "1.3.3"
+ resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127"
+ integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==
+
+tiny-warning@^1.0.0, tiny-warning@^1.0.2, tiny-warning@^1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
+ integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
+
+tinybench@^2.5.1:
+ version "2.8.0"
+ resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.8.0.tgz#30e19ae3a27508ee18273ffed9ac7018949acd7b"
+ integrity sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==
+
+tinypool@^0.8.3:
+ version "0.8.4"
+ resolved "https://registry.yarnpkg.com/tinypool/-/tinypool-0.8.4.tgz#e217fe1270d941b39e98c625dcecebb1408c9aa8"
+ integrity sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==
+
+tinyspy@^2.2.0:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.2.1.tgz#117b2342f1f38a0dbdcc73a50a454883adf861d1"
+ integrity sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==
+
+title-case@^2.1.0:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"
+ integrity sha512-EkJoZ2O3zdCz3zJsYCsxyq2OC5hrxR9mfdd5I+w8h/tmFfeOxJ+vvkxsKxdmN0WtS9zLdHEgfgVOiMVgv+Po4Q==
+ dependencies:
+ no-case "^2.2.0"
+ upper-case "^1.0.3"
+
+titleize@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53"
+ integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==
+
+tmp@^0.0.33:
+ version "0.0.33"
+ resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+ integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+ dependencies:
+ os-tmpdir "~1.0.2"
+
+to-fast-properties@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+ integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
+
+to-object-path@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+ integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg==
+ dependencies:
+ kind-of "^3.0.2"
+
+to-regex-range@^5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+ integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
+ dependencies:
+ is-number "^7.0.0"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+ integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+ dependencies:
+ define-property "^2.0.2"
+ extend-shallow "^3.0.2"
+ regex-not "^1.0.2"
+ safe-regex "^1.1.0"
+
+toidentifier@1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35"
+ integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==
+
+toposort@^2.0.2:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330"
+ integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==
+
+totalist@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8"
+ integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==
+
+touch@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.1.tgz#097a23d7b161476435e5c1344a95c0f75b4a5694"
+ integrity sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==
+
+tr46@~0.0.3:
+ version "0.0.3"
+ resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
+ integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
+
+tree-kill@^1.2.2:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
+ integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==
+
+triple-beam@^1.3.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984"
+ integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==
+
+tslib@2.4.0:
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
+ integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
+
+tslib@^1.10.0, tslib@^1.9.0, tslib@^1.9.3:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+ integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
+
+tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.0:
+ version "2.6.3"
+ resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0"
+ integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
+
+tsscmp@1.0.6:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"
+ integrity sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==
+
+tunnel-agent@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+ integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+type-detect@^4.0.0, type-detect@^4.0.8:
+ version "4.0.8"
+ resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c"
+ integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
+
+type-fest@^0.20.2:
+ version "0.20.2"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4"
+ integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
+
+type-fest@^0.21.3:
+ version "0.21.3"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37"
+ integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==
+
+type-fest@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
+type-fest@^0.8.1:
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+ integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+
+type-fest@^2.18.0:
+ version "2.19.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b"
+ integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==
+
+type-is@^1.6.14, type-is@^1.6.16, type-is@^1.6.18:
+ version "1.6.18"
+ resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+ integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+ dependencies:
+ media-typer "0.3.0"
+ mime-types "~2.1.24"
+
+typedarray-to-buffer@^3.1.5:
+ version "3.1.5"
+ resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
+ integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
+ dependencies:
+ is-typedarray "^1.0.0"
+
+typescript@5.2.2:
+ version "5.2.2"
+ resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78"
+ integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
+
+uc.micro@^1.0.1, uc.micro@^1.0.5:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.6.tgz#9c411a802a409a91fc6cf74081baba34b24499ac"
+ integrity sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==
+
+ufo@^1.5.3:
+ version "1.5.3"
+ resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.5.3.tgz#3325bd3c977b6c6cd3160bf4ff52989adc9d3344"
+ integrity sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==
+
+uglify-js@^3.1.4:
+ version "3.18.0"
+ resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.18.0.tgz#73b576a7e8fda63d2831e293aeead73e0a270deb"
+ integrity sha512-SyVVbcNBCk0dzr9XL/R/ySrmYf0s372K6/hFklzgcp2lBFyXtw4I7BOdDjlLhE1aVqaI/SHWXWmYdlZxuyF38A==
+
+umzug@3.2.1:
+ version "3.2.1"
+ resolved "https://registry.yarnpkg.com/umzug/-/umzug-3.2.1.tgz#01c3a109efb037a10a317d4191be22810c37b195"
+ integrity sha512-XyWQowvP9CKZycKc/Zg9SYWrAWX/gJCE799AUTFqk8yC3tp44K1xWr3LoFF0MNEjClKOo1suCr5ASnoy+KltdA==
+ dependencies:
+ "@rushstack/ts-command-line" "^4.12.2"
+ emittery "^0.12.1"
+ fs-jetpack "^4.3.1"
+ glob "^8.0.3"
+ pony-cause "^2.1.2"
+ type-fest "^2.18.0"
+
+unc-path-regex@^0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
+ integrity sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==
+
+undefsafe@^2.0.5:
+ version "2.0.5"
+ resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
+ integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
+
+undici-types@~5.26.4:
+ version "5.26.5"
+ resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+ integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
+union-value@^1.0.0:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+ integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
+ dependencies:
+ arr-union "^3.1.0"
+ get-value "^2.0.6"
+ is-extendable "^0.1.1"
+ set-value "^2.0.1"
+
+unique-string@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
+ integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
+ dependencies:
+ crypto-random-string "^2.0.0"
+
+universalify@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+ integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
+
+universalify@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d"
+ integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==
+
+unload@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
+ integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
+ dependencies:
+ "@babel/runtime" "^7.6.2"
+ detect-node "^2.0.4"
+
+unpipe@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+ integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==
+
+unset-value@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+ integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==
+ dependencies:
+ has-value "^0.3.1"
+ isobject "^3.0.0"
+
+untildify@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b"
+ integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==
+
+update-browserslist-db@^1.0.16:
+ version "1.0.16"
+ resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz#f6d489ed90fb2f07d67784eb3f53d7891f736356"
+ integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==
+ dependencies:
+ escalade "^3.1.2"
+ picocolors "^1.0.1"
+
+upper-case-first@^1.1.0, upper-case-first@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
+ integrity sha512-wINKYvI3Db8dtjikdAqoBbZoP6Q+PZUyfMR7pmwHzjC2quzSkUq5DmPrTtPEqHaz8AGtmsB4TqwapMTM1QAQOQ==
+ dependencies:
+ upper-case "^1.1.1"
+
+upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3:
+ version "1.1.3"
+ resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+ integrity sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==
+
+uri-js@^4.2.2, uri-js@^4.4.1:
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
+ integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ dependencies:
+ punycode "^2.1.0"
+
+urix@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+ integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg==
+
+url-join@4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7"
+ integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==
+
+url@0.10.3:
+ version "0.10.3"
+ resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64"
+ integrity sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==
+ dependencies:
+ punycode "1.3.2"
+ querystring "0.2.0"
+
+use-callback-ref@^1.3.0:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.2.tgz#6134c7f6ff76e2be0b56c809b17a650c942b1693"
+ integrity sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==
+ dependencies:
+ tslib "^2.0.0"
+
+use-isomorphic-layout-effect@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
+ integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
+
+use-sidecar@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.2.tgz#2f43126ba2d7d7e117aa5855e5d8f0276dfe73c2"
+ integrity sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==
+ dependencies:
+ detect-node-es "^1.1.0"
+ tslib "^2.0.0"
+
+use-sync-external-store@^1.0.0:
+ version "1.2.2"
+ resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.2.tgz#c3b6390f3a30eba13200d2302dcdf1e7b57b2ef9"
+ integrity sha512-PElTlVMwpblvbNqQ82d2n6RjStvdSoNe9FG28kNfz3WiXilJm4DdNkEzRhCZuIDwY8U08WVihhGR5iRqAwfDiw==
+
+use@^3.1.0:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+ integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+user-home@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190"
+ integrity sha512-aggiKfEEubv3UwRNqTzLInZpAOmKzwdHqEBmW/hBA/mt99eg+b4VrX6i+IRLxU8+WJYfa33rGwRseg4eElUgsQ==
+
+util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+ integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+
+util@^0.12.3, util@^0.12.4:
+ version "0.12.5"
+ resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc"
+ integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==
+ dependencies:
+ inherits "^2.0.3"
+ is-arguments "^1.0.4"
+ is-generator-function "^1.0.7"
+ is-typed-array "^1.1.3"
+ which-typed-array "^1.1.2"
+
+utila@~0.4:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
+ integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA==
+
+utils-merge@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+ integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
+
+uuid@8.0.0:
+ version "8.0.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.0.0.tgz#bc6ccf91b5ff0ac07bbcdbf1c7c4e150db4dbb6c"
+ integrity sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==
+
+uuid@^8.3.2:
+ version "8.3.2"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
+ integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
+
+v8flags@^2.0.10:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
+ integrity sha512-SKfhk/LlaXzvtowJabLZwD4K6SGRYeoxA7KJeISlUMAB/NT4CBkZjMq3WceX2Ckm4llwqYVo8TICgsDYCBU2tA==
+ dependencies:
+ user-home "^1.1.1"
+
+validate-npm-package-license@^3.0.1:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+ integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+ dependencies:
+ spdx-correct "^3.0.0"
+ spdx-expression-parse "^3.0.0"
+
+value-equal@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c"
+ integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw==
+
+vary@^1.1.2:
+ version "1.1.2"
+ resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+ integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
+
+viem@^2.14.2:
+ version "2.16.0"
+ resolved "https://registry.yarnpkg.com/viem/-/viem-2.16.0.tgz#646b7a872bc734de210e577f4b3630ffdc110b6d"
+ integrity sha512-qXakKfshaDOiQFgb3MgROKDa4bfr095GMUqrD2WN6UMdzH7WtlAYJ65vnrpoXpny9jXAyNoirEJeBBUF9KFNIQ==
+ dependencies:
+ "@adraffy/ens-normalize" "1.10.0"
+ "@noble/curves" "1.2.0"
+ "@noble/hashes" "1.3.2"
+ "@scure/bip32" "1.3.2"
+ "@scure/bip39" "1.2.1"
+ abitype "1.0.4"
+ isows "1.0.4"
+ ws "8.17.1"
+
+vite-node@1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/vite-node/-/vite-node-1.6.0.tgz#2c7e61129bfecc759478fa592754fd9704aaba7f"
+ integrity sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==
+ dependencies:
+ cac "^6.7.14"
+ debug "^4.3.4"
+ pathe "^1.1.1"
+ picocolors "^1.0.0"
+ vite "^5.0.0"
+
+vite@5.0.13:
+ version "5.0.13"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.13.tgz#605865b0e482506163e3f04f91665238f3be8cf1"
+ integrity sha512-/9ovhv2M2dGTuA+dY93B9trfyWMDRQw2jdVBhHNP6wr0oF34wG2i/N55801iZIpgUpnHDm4F/FabGQLyc+eOgg==
+ dependencies:
+ esbuild "^0.19.3"
+ postcss "^8.4.32"
+ rollup "^4.2.0"
+ optionalDependencies:
+ fsevents "~2.3.3"
+
+vite@^5.0.0:
+ version "5.3.1"
+ resolved "https://registry.yarnpkg.com/vite/-/vite-5.3.1.tgz#bb2ca6b5fd7483249d3e86b25026e27ba8a663e6"
+ integrity sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==
+ dependencies:
+ esbuild "^0.21.3"
+ postcss "^8.4.38"
+ rollup "^4.13.0"
+ optionalDependencies:
+ fsevents "~2.3.3"
+
+vitest@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/vitest/-/vitest-1.6.0.tgz#9d5ad4752a3c451be919e412c597126cffb9892f"
+ integrity sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==
+ dependencies:
+ "@vitest/expect" "1.6.0"
+ "@vitest/runner" "1.6.0"
+ "@vitest/snapshot" "1.6.0"
+ "@vitest/spy" "1.6.0"
+ "@vitest/utils" "1.6.0"
+ acorn-walk "^8.3.2"
+ chai "^4.3.10"
+ debug "^4.3.4"
+ execa "^8.0.1"
+ local-pkg "^0.5.0"
+ magic-string "^0.30.5"
+ pathe "^1.1.1"
+ picocolors "^1.0.0"
+ std-env "^3.5.0"
+ strip-literal "^2.0.0"
+ tinybench "^2.5.1"
+ tinypool "^0.8.3"
+ vite "^5.0.0"
+ vite-node "1.6.0"
+ why-is-node-running "^2.2.2"
+
+w3c-keyname@^2.2.4:
+ version "2.2.8"
+ resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5"
+ integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==
+
+watchpack@^2.4.1:
+ version "2.4.1"
+ resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.1.tgz#29308f2cac150fa8e4c92f90e0ec954a9fed7fff"
+ integrity sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==
+ dependencies:
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.1.2"
+
+wcwidth@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8"
+ integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==
+ dependencies:
+ defaults "^1.0.3"
+
+web-encoding@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/web-encoding/-/web-encoding-1.1.5.tgz#fc810cf7667364a6335c939913f5051d3e0c4864"
+ integrity sha512-HYLeVCdJ0+lBYV2FvNZmv3HJ2Nt0QYXqZojk3d9FJOLkwnuhzM9tmamh8d7HPM8QqjKH8DeHkFTx+CFlWpZZDA==
+ dependencies:
+ util "^0.12.3"
+ optionalDependencies:
+ "@zxing/text-encoding" "0.9.0"
+
+webidl-conversions@^3.0.0:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
+ integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
+
+webpack-bundle-analyzer@^4.10.1:
+ version "4.10.2"
+ resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.2.tgz#633af2862c213730be3dbdf40456db171b60d5bd"
+ integrity sha512-vJptkMm9pk5si4Bv922ZbKLV8UTT4zib4FPgXMhgzUny0bfDDkLXAVQs3ly3fS4/TN9ROFtb0NFrm04UXFE/Vw==
+ dependencies:
+ "@discoveryjs/json-ext" "0.5.7"
+ acorn "^8.0.4"
+ acorn-walk "^8.0.0"
+ commander "^7.2.0"
+ debounce "^1.2.1"
+ escape-string-regexp "^4.0.0"
+ gzip-size "^6.0.0"
+ html-escaper "^2.0.2"
+ opener "^1.5.2"
+ picocolors "^1.0.0"
+ sirv "^2.0.3"
+ ws "^7.3.1"
+
+webpack-dev-middleware@6.1.2:
+ version "6.1.2"
+ resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-6.1.2.tgz#0463232e59b7d7330fa154121528d484d36eb973"
+ integrity sha512-Wu+EHmX326YPYUpQLKmKbTyZZJIB8/n6R09pTmB03kJmnMsVPTo9COzHZFr01txwaCAuZvfBJE4ZCHRcKs5JaQ==
+ dependencies:
+ colorette "^2.0.10"
+ memfs "^3.4.12"
+ mime-types "^2.1.31"
+ range-parser "^1.2.1"
+ schema-utils "^4.0.0"
+
+webpack-hot-middleware@2.26.0:
+ version "2.26.0"
+ resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.26.0.tgz#0a103c9b2836c1f27d7f74bbe0e96c99c82d0265"
+ integrity sha512-okzjec5sAEy4t+7rzdT8eRyxsk0FDSmBPN2KwX4Qd+6+oQCfe5Ve07+u7cJvofgB+B4w5/4dO4Pz0jhhHyyPLQ==
+ dependencies:
+ ansi-html-community "0.0.8"
+ html-entities "^2.1.0"
+ strip-ansi "^6.0.0"
+
+webpack-sources@^1.4.3:
+ version "1.4.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933"
+ integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==
+ dependencies:
+ source-list-map "^2.0.0"
+ source-map "~0.6.1"
+
+webpack-sources@^3.2.3:
+ version "3.2.3"
+ resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
+ integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
+
+webpack@^5.89.0:
+ version "5.92.1"
+ resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.92.1.tgz#eca5c1725b9e189cffbd86e8b6c3c7400efc5788"
+ integrity sha512-JECQ7IwJb+7fgUFBlrJzbyu3GEuNBcdqr1LD7IbSzwkSmIevTm8PF+wej3Oxuz/JFBUZ6O1o43zsPkwm1C4TmA==
+ dependencies:
+ "@types/eslint-scope" "^3.7.3"
+ "@types/estree" "^1.0.5"
+ "@webassemblyjs/ast" "^1.12.1"
+ "@webassemblyjs/wasm-edit" "^1.12.1"
+ "@webassemblyjs/wasm-parser" "^1.12.1"
+ acorn "^8.7.1"
+ acorn-import-attributes "^1.9.5"
+ browserslist "^4.21.10"
+ chrome-trace-event "^1.0.2"
+ enhanced-resolve "^5.17.0"
+ es-module-lexer "^1.2.1"
+ eslint-scope "5.1.1"
+ events "^3.2.0"
+ glob-to-regexp "^0.4.1"
+ graceful-fs "^4.2.11"
+ json-parse-even-better-errors "^2.3.1"
+ loader-runner "^4.2.0"
+ mime-types "^2.1.27"
+ neo-async "^2.6.2"
+ schema-utils "^3.2.0"
+ tapable "^2.1.1"
+ terser-webpack-plugin "^5.3.10"
+ watchpack "^2.4.1"
+ webpack-sources "^3.2.3"
+
+whatwg-url@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
+ integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
+ dependencies:
+ tr46 "~0.0.3"
+ webidl-conversions "^3.0.0"
+
+which-typed-array@^1.1.14, which-typed-array@^1.1.2:
+ version "1.1.15"
+ resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d"
+ integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==
+ dependencies:
+ available-typed-arrays "^1.0.7"
+ call-bind "^1.0.7"
+ for-each "^0.3.3"
+ gopd "^1.0.1"
+ has-tostringtag "^1.0.2"
+
+which@^1.2.14:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+ integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+ dependencies:
+ isexe "^2.0.0"
+
+which@^2.0.1:
+ version "2.0.2"
+ resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
+ integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
+ dependencies:
+ isexe "^2.0.0"
+
+why-is-node-running@^2.2.2:
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/why-is-node-running/-/why-is-node-running-2.2.2.tgz#4185b2b4699117819e7154594271e7e344c9973e"
+ integrity sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==
+ dependencies:
+ siginfo "^2.0.0"
+ stackback "0.0.2"
+
+widest-line@^3.1.0:
+ version "3.1.0"
+ resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
+ integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
+ dependencies:
+ string-width "^4.0.0"
+
+winston-transport@^4.5.0, winston-transport@^4.7.0:
+ version "4.7.0"
+ resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.7.0.tgz#e302e6889e6ccb7f383b926df6936a5b781bd1f0"
+ integrity sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==
+ dependencies:
+ logform "^2.3.2"
+ readable-stream "^3.6.0"
+ triple-beam "^1.3.0"
+
+winston@3.10.0:
+ version "3.10.0"
+ resolved "https://registry.yarnpkg.com/winston/-/winston-3.10.0.tgz#d033cb7bd3ced026fed13bf9d92c55b903116803"
+ integrity sha512-nT6SIDaE9B7ZRO0u3UvdrimG0HkB7dSTAgInQnNR2SOPJ4bvq5q79+pXLftKmP52lJGW15+H5MCK0nM9D3KB/g==
+ dependencies:
+ "@colors/colors" "1.5.0"
+ "@dabh/diagnostics" "^2.0.2"
+ async "^3.2.3"
+ is-stream "^2.0.0"
+ logform "^2.4.0"
+ one-time "^1.0.0"
+ readable-stream "^3.4.0"
+ safe-stable-stringify "^2.3.1"
+ stack-trace "0.0.x"
+ triple-beam "^1.3.0"
+ winston-transport "^4.5.0"
+
+winston@^3.13.0:
+ version "3.13.0"
+ resolved "https://registry.yarnpkg.com/winston/-/winston-3.13.0.tgz#e76c0d722f78e04838158c61adc1287201de7ce3"
+ integrity sha512-rwidmA1w3SE4j0E5MuIufFhyJPBDG7Nu71RkZor1p2+qHvJSZ9GYDA81AyleQcZbh/+V6HjeBdfnTZJm9rSeQQ==
+ dependencies:
+ "@colors/colors" "^1.6.0"
+ "@dabh/diagnostics" "^2.0.2"
+ async "^3.2.3"
+ is-stream "^2.0.0"
+ logform "^2.4.0"
+ one-time "^1.0.0"
+ readable-stream "^3.4.0"
+ safe-stable-stringify "^2.3.1"
+ stack-trace "0.0.x"
+ triple-beam "^1.3.0"
+ winston-transport "^4.7.0"
+
+wordwrap@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+ integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==
+
+"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
+ version "7.0.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
+ integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
+ dependencies:
+ ansi-styles "^4.0.0"
+ string-width "^4.1.0"
+ strip-ansi "^6.0.0"
+
+wrap-ansi@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"
+ integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==
+ dependencies:
+ ansi-styles "^6.1.0"
+ string-width "^5.0.1"
+ strip-ansi "^7.0.1"
+
+wrappy@1:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+ integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
+
+write-file-atomic@^3.0.0:
+ version "3.0.3"
+ resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
+ integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
+ dependencies:
+ imurmurhash "^0.1.4"
+ is-typedarray "^1.0.0"
+ signal-exit "^3.0.2"
+ typedarray-to-buffer "^3.1.5"
+
+ws@8.13.0:
+ version "8.13.0"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
+ integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
+
+ws@8.17.1:
+ version "8.17.1"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
+ integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
+
+ws@^7.3.1:
+ version "7.5.10"
+ resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9"
+ integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==
+
+xdg-app-paths@8.3.0:
+ version "8.3.0"
+ resolved "https://registry.yarnpkg.com/xdg-app-paths/-/xdg-app-paths-8.3.0.tgz#493dbbf6cdf430360a0b4ddabddd6da619b1dbbd"
+ integrity sha512-mgxlWVZw0TNWHoGmXq+NC3uhCIc55dDpAlDkMQUaIAcQzysb0kxctwv//fvuW61/nAAeUBJMQ8mnZjMmuYwOcQ==
+ dependencies:
+ xdg-portable "^10.6.0"
+ optionalDependencies:
+ fsevents "*"
+
+xdg-basedir@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
+ integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
+
+xdg-portable@^10.6.0:
+ version "10.6.0"
+ resolved "https://registry.yarnpkg.com/xdg-portable/-/xdg-portable-10.6.0.tgz#879ef439ace6a95ac5a49eea96c30f6a7819857c"
+ integrity sha512-xrcqhWDvtZ7WLmt8G4f3hHy37iK7D2idtosRgkeiSPZEPmBShp0VfmRBLWAPC6zLF48APJ21yfea+RfQMF4/Aw==
+ dependencies:
+ os-paths "^7.4.0"
+ optionalDependencies:
+ fsevents "*"
+
+xml2js@0.6.2:
+ version "0.6.2"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.6.2.tgz#dd0b630083aa09c161e25a4d0901e2b2a929b499"
+ integrity sha512-T4rieHaC1EXcES0Kxxj4JWgaUQHDk+qwHcYOCFHfiwKz7tOVPLq7Hjq9dM1WCMhylqMEfP7hMcOIChvotiZegA==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~11.0.0"
+
+xml2js@^0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.5.0.tgz#d9440631fbb2ed800203fad106f2724f62c493b7"
+ integrity sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==
+ dependencies:
+ sax ">=0.6.0"
+ xmlbuilder "~11.0.0"
+
+xml@^1.0.1:
+ version "1.0.1"
+ resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5"
+ integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==
+
+xmlbuilder@~11.0.0:
+ version "11.0.1"
+ resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
+ integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
+
+xtend@^4.0.0, xtend@~4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+ integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+y18n@^5.0.5:
+ version "5.0.8"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55"
+ integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==
+
+yalc@1.0.0-pre.53:
+ version "1.0.0-pre.53"
+ resolved "https://registry.yarnpkg.com/yalc/-/yalc-1.0.0-pre.53.tgz#c51db2bb924a6908f4cb7e82af78f7e5606810bc"
+ integrity sha512-tpNqBCpTXplnduzw5XC+FF8zNJ9L/UXmvQyyQj7NKrDNavbJtHvzmZplL5ES/RCnjX7JR7W9wz5GVDXVP3dHUQ==
+ dependencies:
+ chalk "^4.1.0"
+ detect-indent "^6.0.0"
+ fs-extra "^8.0.1"
+ glob "^7.1.4"
+ ignore "^5.0.4"
+ ini "^2.0.0"
+ npm-packlist "^2.1.5"
+ yargs "^16.1.1"
+
+yallist@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
+ integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
+
+yallist@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/yallist/-/yallist-5.0.0.tgz#00e2de443639ed0d78fd87de0d27469fbcffb533"
+ integrity sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==
+
+yaml@^1.10.0:
+ version "1.10.2"
+ resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
+ integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
+
+yargs-parser@^20.2.2:
+ version "20.2.9"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee"
+ integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==
+
+yargs-parser@^21.1.1:
+ version "21.1.1"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35"
+ integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==
+
+yargs@^16.1.0, yargs@^16.1.1:
+ version "16.2.0"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66"
+ integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==
+ dependencies:
+ cliui "^7.0.2"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.0"
+ y18n "^5.0.5"
+ yargs-parser "^20.2.2"
+
+yargs@^17.7.2:
+ version "17.7.2"
+ resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269"
+ integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==
+ dependencies:
+ cliui "^8.0.1"
+ escalade "^3.1.1"
+ get-caller-file "^2.0.5"
+ require-directory "^2.1.1"
+ string-width "^4.2.3"
+ y18n "^5.0.5"
+ yargs-parser "^21.1.1"
+
+ylru@^1.2.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.4.0.tgz#0cf0aa57e9c24f8a2cbde0cc1ca2c9592ac4e0f6"
+ integrity sha512-2OQsPNEmBCvXuFlIni/a+Rn+R2pHW9INm0BxXJ4hVDA8TirqMj+J/Rp9ItLatT/5pZqWwefVrTQcHpixsxnVlA==
+
+yocto-queue@^0.1.0:
+ version "0.1.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
+ integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
+
+yocto-queue@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-1.0.0.tgz#7f816433fb2cbc511ec8bf7d263c3b58a1a3c251"
+ integrity sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==
+
+yup@0.32.9:
+ version "0.32.9"
+ resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.9.tgz#9367bec6b1b0e39211ecbca598702e106019d872"
+ integrity sha512-Ci1qN+i2H0XpY7syDQ0k5zKQ/DoxO0LzPg8PAR/X4Mpj6DqaeCoIYEEjDJwhArh3Fa7GWbQQVDZKeXYlSH4JMg==
+ dependencies:
+ "@babel/runtime" "^7.10.5"
+ "@types/lodash" "^4.14.165"
+ lodash "^4.17.20"
+ lodash-es "^4.17.15"
+ nanoclone "^0.2.1"
+ property-expr "^2.0.4"
+ toposort "^2.0.2"
diff --git a/packages/apps/dashboard/server/.env.example b/packages/apps/dashboard/server/.env.example
new file mode 100644
index 0000000000..f92510100f
--- /dev/null
+++ b/packages/apps/dashboard/server/.env.example
@@ -0,0 +1,19 @@
+# App
+NODE_ENV=development
+HOST=localhost
+PORT=3000
+CORS_ENABLED=
+CORS_ALLOWED_ORIGIN=
+CORS_ALLOWED_HEADERS=
+SUBGRAPH_API_KEY=
+HMT_PRICE_SOURCE=
+HMT_PRICE_SOURCE_API_KEY=
+HMT_PRICE_FROM=
+HMT_PRICE_TO=
+
+# Redis
+REDIS_HOST=localhost
+REDIS_PORT=6379
+CACHE_HMT_PRICE_TTL=60
+CACHE_HMT_GENERAL_STATS_TTL=120
+HMT_PRICE_CACHE_KEY=
\ No newline at end of file
diff --git a/packages/apps/dashboard/server/.eslintrc.js b/packages/apps/dashboard/server/.eslintrc.js
new file mode 100644
index 0000000000..259de13c73
--- /dev/null
+++ b/packages/apps/dashboard/server/.eslintrc.js
@@ -0,0 +1,25 @@
+module.exports = {
+ parser: '@typescript-eslint/parser',
+ parserOptions: {
+ project: 'tsconfig.json',
+ tsconfigRootDir: __dirname,
+ sourceType: 'module',
+ },
+ plugins: ['@typescript-eslint/eslint-plugin'],
+ extends: [
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:prettier/recommended',
+ ],
+ root: true,
+ env: {
+ node: true,
+ jest: true,
+ },
+ ignorePatterns: ['.eslintrc.js'],
+ rules: {
+ '@typescript-eslint/interface-name-prefix': 'off',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
+ },
+};
diff --git a/packages/apps/dashboard/server/.gitignore b/packages/apps/dashboard/server/.gitignore
new file mode 100644
index 0000000000..336f365e64
--- /dev/null
+++ b/packages/apps/dashboard/server/.gitignore
@@ -0,0 +1,38 @@
+# compiled output
+/dist
+/node_modules
+
+# Logs
+logs
+*.log
+npm-debug.log*
+pnpm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# OS
+.DS_Store
+
+# Tests
+/coverage
+/.nyc_output
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+.c9/
+*.launch
+.settings/
+*.sublime-workspace
+
+# IDE - VSCode
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+# Redis Data
+/redis_data
\ No newline at end of file
diff --git a/packages/apps/dashboard/server/.prettierrc b/packages/apps/dashboard/server/.prettierrc
new file mode 100644
index 0000000000..dcb72794f5
--- /dev/null
+++ b/packages/apps/dashboard/server/.prettierrc
@@ -0,0 +1,4 @@
+{
+ "singleQuote": true,
+ "trailingComma": "all"
+}
\ No newline at end of file
diff --git a/packages/apps/dashboard/server/README.md b/packages/apps/dashboard/server/README.md
new file mode 100644
index 0000000000..83729419a3
--- /dev/null
+++ b/packages/apps/dashboard/server/README.md
@@ -0,0 +1,73 @@
+
+
+
+
+[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
+[circleci-url]: https://circleci.com/gh/nestjs/nest
+
+ A progressive Node.js framework for building efficient and scalable server-side applications.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+## Description
+
+[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
+
+## Installation
+
+```bash
+$ yarn install
+```
+
+## Running the app
+
+```bash
+# development
+$ yarn run start
+
+# watch mode
+$ yarn run start:dev
+
+# production mode
+$ yarn run start:prod
+```
+
+## Test
+
+```bash
+# unit tests
+$ yarn run test
+
+# e2e tests
+$ yarn run test:e2e
+
+# test coverage
+$ yarn run test:cov
+```
+
+## Support
+
+Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
+
+## Stay in touch
+
+- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com)
+- Website - [https://nestjs.com](https://nestjs.com/)
+- Twitter - [@nestframework](https://twitter.com/nestframework)
+
+## License
+
+Nest is [MIT licensed](LICENSE).
diff --git a/packages/apps/dashboard/server/docker-compose.yml b/packages/apps/dashboard/server/docker-compose.yml
new file mode 100644
index 0000000000..7cd8879212
--- /dev/null
+++ b/packages/apps/dashboard/server/docker-compose.yml
@@ -0,0 +1,10 @@
+version: '3.8'
+
+services:
+ redis:
+ image: redis:latest
+ container_name: dashboard-cache
+ ports:
+ - '6379:6379'
+ volumes:
+ - ./redis_data:/data
\ No newline at end of file
diff --git a/packages/apps/dashboard/server/nest-cli.json b/packages/apps/dashboard/server/nest-cli.json
new file mode 100644
index 0000000000..f9aa683b1a
--- /dev/null
+++ b/packages/apps/dashboard/server/nest-cli.json
@@ -0,0 +1,8 @@
+{
+ "$schema": "https://json.schemastore.org/nest-cli",
+ "collection": "@nestjs/schematics",
+ "sourceRoot": "src",
+ "compilerOptions": {
+ "deleteOutDir": true
+ }
+}
diff --git a/packages/apps/dashboard/server/package.json b/packages/apps/dashboard/server/package.json
new file mode 100644
index 0000000000..6449ed471b
--- /dev/null
+++ b/packages/apps/dashboard/server/package.json
@@ -0,0 +1,59 @@
+{
+ "name": "@human-protocol/dashboard-server",
+ "version": "0.0.1",
+ "description": "",
+ "author": "",
+ "private": true,
+ "license": "UNLICENSED",
+ "scripts": {
+ "build": "nest build",
+ "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
+ "start": "nest start",
+ "start:dev": "nest start --watch",
+ "start:debug": "nest start --debug --watch",
+ "start:prod": "node dist/main",
+ "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
+ },
+ "dependencies": {
+ "@human-protocol/sdk": "*",
+ "@nestjs/axios": "^3.0.2",
+ "@nestjs/cache-manager": "^2.2.2",
+ "@nestjs/common": "^10.2.7",
+ "@nestjs/config": "^3.2.3",
+ "@nestjs/core": "^10.2.8",
+ "@nestjs/mapped-types": "*",
+ "@nestjs/platform-express": "^10.3.10",
+ "cache-manager-redis-store": "^3.0.1",
+ "reflect-metadata": "^0.2.2",
+ "rxjs": "^7.2.0"
+ },
+ "devDependencies": {
+ "@nestjs/cli": "^10.3.2",
+ "@nestjs/schematics": "^10.1.3",
+ "@nestjs/testing": "^9.4.3",
+ "@types/express": "^4.17.13",
+ "@types/jest": "29.5.1",
+ "@types/node": "18.16.12",
+ "@types/supertest": "^2.0.11",
+ "@typescript-eslint/eslint-plugin": "^5.0.0",
+ "@typescript-eslint/parser": "^5.0.0",
+ "eslint": "^8.0.1",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-plugin-prettier": "^4.0.0",
+ "jest": "29.5.0",
+ "prettier": "^2.3.2",
+ "source-map-support": "^0.5.20",
+ "supertest": "^6.1.3",
+ "ts-jest": "29.2.2",
+ "ts-loader": "^9.2.3",
+ "ts-node": "^10.0.0",
+ "tsconfig-paths": "4.2.0",
+ "typescript": "^5.0.0"
+ },
+ "lint-staged": {
+ "*.ts": [
+ "prettier --write",
+ "eslint --fix"
+ ]
+ }
+}
diff --git a/packages/apps/dashboard/server/src/app.controller.ts b/packages/apps/dashboard/server/src/app.controller.ts
new file mode 100644
index 0000000000..f6cc9bb67c
--- /dev/null
+++ b/packages/apps/dashboard/server/src/app.controller.ts
@@ -0,0 +1,12 @@
+import { Controller, Get, Redirect } from '@nestjs/common';
+import { ApiExcludeEndpoint } from '@nestjs/swagger';
+
+@Controller()
+export class AppController {
+ @Get('/')
+ @Redirect('/swagger', 301)
+ @ApiExcludeEndpoint()
+ public swagger(): string {
+ return 'OK';
+ }
+}
diff --git a/packages/apps/dashboard/server/src/app.module.ts b/packages/apps/dashboard/server/src/app.module.ts
new file mode 100644
index 0000000000..11b9c393e9
--- /dev/null
+++ b/packages/apps/dashboard/server/src/app.module.ts
@@ -0,0 +1,35 @@
+import { CacheModule } from '@nestjs/cache-manager';
+import { ConfigModule } from '@nestjs/config';
+import { Module } from '@nestjs/common';
+
+import * as Joi from 'joi';
+
+import { AppController } from './app.controller';
+import { CacheFactoryConfig } from './common/config/cache-factory.config';
+import { CommonConfigModule } from './common/config/config.module';
+import { DetailsModule } from './modules/details/details.module';
+import { RedisModule } from './modules/redis/redis.module';
+import { StatsModule } from './modules/stats/stats.module';
+
+@Module({
+ imports: [
+ ConfigModule.forRoot({
+ envFilePath: process.env.NODE_ENV
+ ? `.env.${process.env.NODE_ENV as string}`
+ : '.env',
+ isGlobal: true,
+ validationSchema: Joi.object({
+ HOST: Joi.string().required(),
+ PORT: Joi.number().port().default(3000),
+ SUBGRAPH_API_KEY: Joi.string().required(),
+ }),
+ }),
+ CacheModule.registerAsync(CacheFactoryConfig),
+ CommonConfigModule,
+ DetailsModule,
+ RedisModule,
+ StatsModule,
+ ],
+ controllers: [AppController],
+})
+export class AppModule {}
diff --git a/packages/apps/dashboard/server/src/common/config/cache-factory.config.ts b/packages/apps/dashboard/server/src/common/config/cache-factory.config.ts
new file mode 100644
index 0000000000..5919724fe8
--- /dev/null
+++ b/packages/apps/dashboard/server/src/common/config/cache-factory.config.ts
@@ -0,0 +1,21 @@
+import { CacheModuleAsyncOptions } from '@nestjs/common/cache';
+import { ConfigModule } from '@nestjs/config';
+import { RedisConfigService } from './redis-config.service';
+import { redisStore } from 'cache-manager-redis-store';
+
+export const CacheFactoryConfig: CacheModuleAsyncOptions = {
+ isGlobal: true,
+ imports: [ConfigModule],
+ useFactory: async (configService: RedisConfigService) => {
+ const store = await redisStore({
+ socket: {
+ host: configService.redisHost,
+ port: configService.redisPort,
+ },
+ });
+ return {
+ store: () => store,
+ };
+ },
+ inject: [RedisConfigService],
+};
diff --git a/packages/apps/dashboard/server/src/common/config/config.module.ts b/packages/apps/dashboard/server/src/common/config/config.module.ts
new file mode 100644
index 0000000000..dd1e9fe682
--- /dev/null
+++ b/packages/apps/dashboard/server/src/common/config/config.module.ts
@@ -0,0 +1,10 @@
+import { Module, Global } from '@nestjs/common';
+import { EnvironmentConfigService } from './env-config.service';
+import { RedisConfigService } from './redis-config.service';
+
+@Global()
+@Module({
+ providers: [RedisConfigService, EnvironmentConfigService],
+ exports: [RedisConfigService, EnvironmentConfigService],
+})
+export class CommonConfigModule {}
diff --git a/packages/apps/dashboard/server/src/common/config/env-config.service.ts b/packages/apps/dashboard/server/src/common/config/env-config.service.ts
new file mode 100644
index 0000000000..e5f2a5bd92
--- /dev/null
+++ b/packages/apps/dashboard/server/src/common/config/env-config.service.ts
@@ -0,0 +1,57 @@
+import { ConfigService } from '@nestjs/config';
+import { Injectable } from '@nestjs/common';
+
+const DEFAULT_CORS_ALLOWED_ORIGIN = 'http://localhost:3001';
+const DEFAULT_CORS_ALLOWED_HEADERS = 'Content-Type, Accept';
+
+const DEFAULT_HMT_PRICE_SOURCE =
+ 'https://api.coingecko.com/api/v3/simple/price?ids=human-protocol&vs_currencies=usd';
+const DEFAULT_HMT_PRICE_FROM = 'human-protocol';
+const DEFAULT_HMT_PRICE_TO = 'usd';
+
+@Injectable()
+export class EnvironmentConfigService {
+ constructor(private configService: ConfigService) {}
+ get host(): string {
+ return this.configService.getOrThrow('HOST');
+ }
+ get port(): number {
+ return +this.configService.getOrThrow('PORT');
+ }
+ get isCorsEnabled(): boolean {
+ return this.configService.get('CORS_ENABLED', false);
+ }
+ get corsEnabledOrigin(): string {
+ return this.configService.get(
+ 'CORS_ALLOWED_ORIGIN',
+ DEFAULT_CORS_ALLOWED_ORIGIN,
+ );
+ }
+ get corsAllowedHeaders(): string {
+ return this.configService.get(
+ 'CORS_ALLOWED_HEADERS',
+ DEFAULT_CORS_ALLOWED_HEADERS,
+ );
+ }
+ get subgraphApiKey(): string {
+ return this.configService.getOrThrow('SUBGRAPH_API_KEY');
+ }
+ get hmtPriceSource(): string {
+ return this.configService.get(
+ 'HMT_PRICE_SOURCE',
+ DEFAULT_HMT_PRICE_SOURCE,
+ );
+ }
+ get hmtPriceSourceApiKey(): string {
+ return this.configService.getOrThrow('HMT_PRICE_SOURCE_API_KEY');
+ }
+ get hmtPriceFromKey(): string {
+ return this.configService.get(
+ 'HMT_PRICE_FROM',
+ DEFAULT_HMT_PRICE_FROM,
+ );
+ }
+ get hmtPriceToKey(): string {
+ return this.configService.get('HMT_PRICE_TO', DEFAULT_HMT_PRICE_TO);
+ }
+}
diff --git a/packages/apps/dashboard/server/src/common/config/redis-config.service.ts b/packages/apps/dashboard/server/src/common/config/redis-config.service.ts
new file mode 100644
index 0000000000..36024f030c
--- /dev/null
+++ b/packages/apps/dashboard/server/src/common/config/redis-config.service.ts
@@ -0,0 +1,37 @@
+import { ConfigService } from '@nestjs/config';
+import { Injectable } from '@nestjs/common';
+
+const DEFAULT_REDIS_HOST = 'localhost';
+const DEFAULT_REDIS_PORT = 6379;
+const DEFAULT_CACHE_HMT_PRICE_TTL = 60;
+const DEFAULT_CACHE_HMT_GENERAL_STATS_TTL = 2 * 60;
+const DEFAULT_HMT_PRICE_CACHE_KEY = 'hmt-price';
+
+@Injectable()
+export class RedisConfigService {
+ constructor(private configService: ConfigService) {}
+ get redisHost(): string {
+ return this.configService.get('REDIS_HOST', DEFAULT_REDIS_HOST);
+ }
+ get redisPort(): number {
+ return +this.configService.get('REDIS_PORT', DEFAULT_REDIS_PORT);
+ }
+ get cacheHmtPriceTTL(): number {
+ return +this.configService.get(
+ 'CACHE_HMT_PRICE_TTL',
+ DEFAULT_CACHE_HMT_PRICE_TTL,
+ );
+ }
+ get cacheHmtGeneralStatsTTL(): number {
+ return +this.configService.get(
+ 'CACHE_HMT_GENERAL_STATS_TTL',
+ DEFAULT_CACHE_HMT_GENERAL_STATS_TTL,
+ );
+ }
+ get hmtPriceCacheKey(): string {
+ return this.configService.get(
+ 'HMT_PRICE_CACHE_KEY',
+ DEFAULT_HMT_PRICE_CACHE_KEY,
+ );
+ }
+}
diff --git a/packages/apps/dashboard/server/src/common/pipes/address-validation.pipe.ts b/packages/apps/dashboard/server/src/common/pipes/address-validation.pipe.ts
new file mode 100644
index 0000000000..9a78b6e355
--- /dev/null
+++ b/packages/apps/dashboard/server/src/common/pipes/address-validation.pipe.ts
@@ -0,0 +1,12 @@
+import { PipeTransform, Injectable, BadRequestException } from '@nestjs/common';
+import { ethers } from 'ethers';
+
+@Injectable()
+export class AddressValidationPipe implements PipeTransform {
+ transform(value: string) {
+ if (!ethers.isAddress(value)) {
+ throw new BadRequestException('Invalid address');
+ }
+ return value;
+ }
+}
diff --git a/packages/apps/dashboard/server/src/main.ts b/packages/apps/dashboard/server/src/main.ts
new file mode 100644
index 0000000000..d4bc1caa55
--- /dev/null
+++ b/packages/apps/dashboard/server/src/main.ts
@@ -0,0 +1,41 @@
+import { NestFactory } from '@nestjs/core';
+import { ConfigService } from '@nestjs/config';
+import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
+
+import { AppModule } from './app.module';
+import { EnvironmentConfigService } from './common/config/env-config.service';
+
+async function bootstrap() {
+ const app = await NestFactory.create(AppModule, {
+ logger:
+ process.env.NODE_ENV === 'development'
+ ? ['log', 'debug', 'error', 'verbose', 'warn']
+ : ['log', 'error', 'warn'],
+ });
+
+ const configService: ConfigService = app.get(ConfigService);
+
+ const envConfigService = new EnvironmentConfigService(configService);
+
+ if (envConfigService.isCorsEnabled) {
+ app.enableCors({
+ origin: envConfigService.corsEnabledOrigin,
+ allowedHeaders: envConfigService.corsAllowedHeaders,
+ });
+ }
+ const config = new DocumentBuilder()
+ .setTitle('Dashboard API')
+ .setDescription('Swagger Dashboar API')
+ .setVersion('1.0')
+ .build();
+ const document = SwaggerModule.createDocument(app, config);
+ SwaggerModule.setup('swagger', app, document);
+
+ const host = envConfigService.host;
+ const port = envConfigService.port;
+
+ await app.listen(port, host, async () => {
+ console.info(`Dashboard server is running on http://${host}:${port}`);
+ });
+}
+bootstrap();
diff --git a/packages/apps/dashboard/server/src/modules/details/details.controller.ts b/packages/apps/dashboard/server/src/modules/details/details.controller.ts
new file mode 100644
index 0000000000..167f8403f8
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/details.controller.ts
@@ -0,0 +1,141 @@
+import { ApiOperation, ApiResponse, ApiTags, ApiQuery } from '@nestjs/swagger';
+import {
+ Controller,
+ Get,
+ HttpCode,
+ Param,
+ Query,
+ UsePipes,
+ ValidationPipe,
+} from '@nestjs/common';
+import { ChainId } from '@human-protocol/sdk';
+
+import { AddressValidationPipe } from '../../common/pipes/address-validation.pipe';
+import { DetailsService } from './details.service';
+import {
+ DetailsResponseDto,
+ DetailsPaginationResponseDto,
+} from './dto/details-response.dto';
+import {
+ DetailsTransactionsPaginationDto,
+ DetailsEscrowsPaginationDto,
+} from './dto/details-pagination.dto';
+import { WalletDto } from './dto/wallet.dto';
+import { EscrowDto, EscrowPaginationDto } from './dto/escrow.dto';
+import { LeaderDto } from './dto/leader.dto';
+import { TransactionPaginationDto } from './dto/transaction.dto';
+
+@ApiTags('Details')
+@Controller('/details')
+@UsePipes(new ValidationPipe({ transform: true }))
+export class DetailsController {
+ constructor(private readonly detailsService: DetailsService) {}
+
+ @Get('/:address')
+ @ApiQuery({ name: 'chainId', enum: ChainId })
+ @HttpCode(200)
+ @ApiOperation({
+ summary: 'Get address details',
+ description: 'Returns details about given address.',
+ })
+ @ApiResponse({
+ status: 200,
+ description: 'Details retrieved successfully',
+ type: DetailsResponseDto,
+ })
+ public async details(
+ @Param('address', AddressValidationPipe) address: string,
+ @Query('chainId') chainId: ChainId,
+ ): Promise {
+ const details: WalletDto | EscrowDto | LeaderDto =
+ await this.detailsService.getDetails(chainId, address);
+ if (details instanceof WalletDto) {
+ const response: DetailsResponseDto = {
+ wallet: details,
+ };
+ return response;
+ }
+ if (details instanceof EscrowDto) {
+ const response: DetailsResponseDto = {
+ escrow: details,
+ };
+ return response;
+ }
+ if (details instanceof LeaderDto) {
+ const response: DetailsResponseDto = {
+ leader: details,
+ };
+ return response;
+ }
+ }
+
+ @Get('/transactions/:address')
+ @ApiQuery({ name: 'chainId', enum: ChainId })
+ @HttpCode(200)
+ @ApiOperation({
+ summary: 'Get transactions by address',
+ description: 'Returns transactions for a given address.',
+ })
+ @ApiResponse({
+ status: 200,
+ description: 'Transactions retrieved successfully',
+ type: DetailsPaginationResponseDto,
+ })
+ public async transactions(
+ @Param('address', AddressValidationPipe) address: string,
+ @Query() query: DetailsTransactionsPaginationDto,
+ ): Promise {
+ const transactions: TransactionPaginationDto[] =
+ await this.detailsService.getTransactions(
+ query.chainId,
+ address,
+ query.first,
+ query.skip,
+ );
+
+ const response: DetailsPaginationResponseDto = {
+ address,
+ chainId: query.chainId,
+ first: query.first,
+ skip: query.skip,
+ results: transactions,
+ };
+
+ return response;
+ }
+
+ @Get('/escrows/:address')
+ @ApiQuery({ name: 'chainId', enum: ChainId })
+ @HttpCode(200)
+ @ApiOperation({
+ summary: 'Get escrows by address',
+ description: 'Returns escrows for a given address.',
+ })
+ @ApiResponse({
+ status: 200,
+ description: 'Escrows retrieved successfully',
+ type: DetailsPaginationResponseDto,
+ })
+ public async escrows(
+ @Param('address', AddressValidationPipe) address: string,
+ @Query() query: DetailsEscrowsPaginationDto,
+ ): Promise {
+ const escrows: EscrowPaginationDto[] = await this.detailsService.getEscrows(
+ query.chainId,
+ query.role,
+ address,
+ query.first,
+ query.skip,
+ );
+
+ const response: DetailsPaginationResponseDto = {
+ address,
+ chainId: query.chainId,
+ first: query.first,
+ skip: query.skip,
+ results: escrows,
+ };
+
+ return response;
+ }
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/details.module.ts b/packages/apps/dashboard/server/src/modules/details/details.module.ts
new file mode 100644
index 0000000000..c6e8cee5cf
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/details.module.ts
@@ -0,0 +1,10 @@
+import { Module } from '@nestjs/common';
+
+import { DetailsService } from './details.service';
+import { DetailsController } from './details.controller';
+
+@Module({
+ controllers: [DetailsController],
+ providers: [DetailsService],
+})
+export class DetailsModule {}
diff --git a/packages/apps/dashboard/server/src/modules/details/details.service.ts b/packages/apps/dashboard/server/src/modules/details/details.service.ts
new file mode 100644
index 0000000000..4d68802299
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/details.service.ts
@@ -0,0 +1,120 @@
+import { plainToInstance } from 'class-transformer';
+
+import { Injectable, Logger } from '@nestjs/common';
+import {
+ ChainId,
+ EscrowUtils,
+ TransactionUtils,
+ OperatorUtils,
+ IEscrowsFilter,
+ Role,
+} from '@human-protocol/sdk';
+
+import { WalletDto } from './dto/wallet.dto';
+import { EscrowDto, EscrowPaginationDto } from './dto/escrow.dto';
+import { LeaderDto } from './dto/leader.dto';
+import { TransactionPaginationDto } from './dto/transaction.dto';
+
+@Injectable()
+export class DetailsService {
+ private readonly logger = new Logger(DetailsService.name);
+ public async getDetails(
+ chainId: ChainId,
+ address: string,
+ ): Promise {
+ const escrowData = await EscrowUtils.getEscrow(chainId, address);
+ if (escrowData) {
+ const escrowDto: EscrowDto = plainToInstance(EscrowDto, escrowData, {
+ excludeExtraneousValues: true,
+ });
+ return escrowDto;
+ }
+ const leaderData = await OperatorUtils.getLeader(chainId, address);
+ if (leaderData) {
+ const leaderDto: LeaderDto = plainToInstance(LeaderDto, leaderData, {
+ excludeExtraneousValues: true,
+ });
+
+ leaderDto.address = address;
+ leaderDto.chainId = chainId;
+ // TODO: Balance fetching
+ leaderDto.balance = '0.01';
+
+ return leaderDto;
+ }
+ const walletDto: WalletDto = plainToInstance(WalletDto, {
+ chainId,
+ address,
+ // TODO: Balance fetching
+ balance: '0.01',
+ });
+
+ return walletDto;
+ }
+
+ public async getTransactions(
+ chainId: ChainId,
+ address: string,
+ first: number,
+ skip: number,
+ ): Promise {
+ // TODO: Switch to fetch all transactions related to this wallet address once SDK is changed
+ const transactions = await TransactionUtils.getTransactions({
+ chainId,
+ fromAddress: address,
+ first,
+ skip,
+ });
+ const result = transactions.map((transaction) => {
+ const transcationPaginationObject: TransactionPaginationDto =
+ plainToInstance(TransactionPaginationDto, transaction, {
+ excludeExtraneousValues: true,
+ });
+ return transcationPaginationObject;
+ });
+
+ return result;
+ }
+
+ public async getEscrows(
+ chainId: ChainId,
+ role: string,
+ address: string,
+ first: number,
+ skip: number,
+ ): Promise {
+ const filter: IEscrowsFilter = {
+ chainId,
+ first,
+ skip,
+ };
+
+ switch (role) {
+ case Role.JobLauncher:
+ filter.launcher = address;
+ break;
+ case Role.ReputationOracle:
+ filter.reputationOracle = address;
+ break;
+ case Role.RecordingOracle:
+ filter.recordingOracle = address;
+ break;
+ case Role.ExchangeOracle:
+ filter.exchangeOracle = address;
+ break;
+ }
+ const escrows = await EscrowUtils.getEscrows(filter);
+ const result = escrows.map((escrow) => {
+ const escrowPaginationObject: EscrowPaginationDto = plainToInstance(
+ EscrowPaginationDto,
+ escrow,
+ {
+ excludeExtraneousValues: true,
+ },
+ );
+ return escrowPaginationObject;
+ });
+
+ return result;
+ }
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/dto/details-pagination.dto.ts b/packages/apps/dashboard/server/src/modules/details/dto/details-pagination.dto.ts
new file mode 100644
index 0000000000..e0ffd8a23c
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/dto/details-pagination.dto.ts
@@ -0,0 +1,76 @@
+import { Transform, Type } from 'class-transformer';
+import {
+ IsEnum,
+ IsNumber,
+ IsOptional,
+ IsString,
+ Min,
+ Max,
+} from 'class-validator';
+import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
+import { ChainId } from '@human-protocol/sdk';
+
+import { IsRoleValid } from './validation/role-validation';
+
+export class DetailsTransactionsPaginationDto {
+ @ApiProperty()
+ @IsEnum(ChainId)
+ @Transform(({ value }) => parseInt(value))
+ public chainId: ChainId;
+
+ @ApiPropertyOptional({
+ minimum: 0,
+ default: 10,
+ })
+ @Type(() => Number)
+ @IsNumber()
+ @Min(0)
+ @Max(1000)
+ @IsOptional()
+ public first?: number = 10;
+
+ @ApiPropertyOptional({
+ minimum: 0,
+ default: 0,
+ })
+ @Type(() => Number)
+ @IsNumber()
+ @Min(0)
+ @Max(1000)
+ @IsOptional()
+ public skip?: number = 0;
+}
+
+export class DetailsEscrowsPaginationDto {
+ @ApiProperty()
+ @IsEnum(ChainId)
+ @Transform(({ value }) => parseInt(value))
+ public chainId: ChainId;
+
+ @ApiProperty()
+ @IsString()
+ @IsRoleValid()
+ public role: string;
+
+ @ApiPropertyOptional({
+ minimum: 0,
+ default: 10,
+ })
+ @Type(() => Number)
+ @IsNumber()
+ @Min(0)
+ @Max(1000)
+ @IsOptional()
+ public first?: number = 10;
+
+ @ApiPropertyOptional({
+ minimum: 0,
+ default: 0,
+ })
+ @Type(() => Number)
+ @IsNumber()
+ @Min(0)
+ @Max(1000)
+ @IsOptional()
+ public skip?: number = 0;
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/dto/details-response.dto.ts b/packages/apps/dashboard/server/src/modules/details/dto/details-response.dto.ts
new file mode 100644
index 0000000000..492c31b633
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/dto/details-response.dto.ts
@@ -0,0 +1,43 @@
+import { IsArray, IsOptional } from 'class-validator';
+import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
+import { ChainId } from '@human-protocol/sdk';
+
+import { EscrowDto, EscrowPaginationDto } from './escrow.dto';
+import { TransactionPaginationDto } from './transaction.dto';
+import { LeaderDto } from './leader.dto';
+import { WalletDto } from './wallet.dto';
+
+export class DetailsResponseDto {
+ @ApiProperty()
+ @ApiPropertyOptional()
+ @IsOptional()
+ public wallet?: WalletDto;
+
+ @ApiProperty()
+ @ApiPropertyOptional()
+ @IsOptional()
+ public escrow?: EscrowDto;
+
+ @ApiProperty()
+ @ApiPropertyOptional()
+ @IsOptional()
+ public leader?: LeaderDto;
+}
+
+export class DetailsPaginationResponseDto {
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ public address: string;
+
+ @ApiProperty({ example: ChainId.POLYGON_AMOY })
+ public chainId: ChainId;
+
+ @ApiProperty({ example: 10 })
+ public first: number;
+
+ @ApiProperty({ example: 0 })
+ public skip: number;
+
+ @ApiProperty()
+ @IsArray()
+ public results: EscrowPaginationDto[] | TransactionPaginationDto[];
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/dto/escrow.dto.ts b/packages/apps/dashboard/server/src/modules/details/dto/escrow.dto.ts
new file mode 100644
index 0000000000..4f48910aa5
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/dto/escrow.dto.ts
@@ -0,0 +1,93 @@
+import { Expose } from 'class-transformer';
+import { IsEnum, IsString, IsUrl } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+import { ChainId } from '@human-protocol/sdk';
+
+export class EscrowDto {
+ @ApiProperty({ example: ChainId.POLYGON_AMOY })
+ @IsEnum(ChainId)
+ @Expose()
+ public chainId: ChainId;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ @Expose()
+ public address: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @IsString()
+ @Expose()
+ public balance: string;
+
+ @ApiProperty({ example: 'HMT' })
+ @IsString()
+ @Expose()
+ public token: string;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ @Expose()
+ public factoryAddress: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @IsString()
+ @Expose()
+ public totalFundedAmount: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @IsString()
+ @Expose()
+ public amountPaid: string;
+
+ @ApiProperty({ example: 'Launched' })
+ @IsString()
+ @Expose()
+ public status: string;
+
+ @ApiProperty({ example: 'https://example.test/manifest' })
+ @IsUrl()
+ @Expose()
+ public manifest?: string;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ @Expose()
+ public launcher: string;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ @Expose()
+ public exchangeOracle?: string;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ @Expose()
+ public recordingOracle?: string;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ @Expose()
+ public reputationOracle?: string;
+
+ @ApiProperty({ example: 'https://example.test/final-results' })
+ @IsUrl()
+ @Expose()
+ public finalResultsUrl?: string;
+}
+
+export class EscrowPaginationDto {
+ @ApiProperty({ example: ChainId.POLYGON_AMOY })
+ @IsEnum(ChainId)
+ @Expose()
+ public chainId: ChainId;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ @Expose()
+ public address: string;
+
+ @ApiProperty({ example: 'Launched' })
+ @IsString()
+ @Expose()
+ public status: string;
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/dto/leader.dto.ts b/packages/apps/dashboard/server/src/modules/details/dto/leader.dto.ts
new file mode 100644
index 0000000000..5b15d17f9a
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/dto/leader.dto.ts
@@ -0,0 +1,92 @@
+import { Expose, Transform } from 'class-transformer';
+import {
+ IsArray,
+ IsEnum,
+ IsString,
+ IsUrl,
+ IsOptional,
+ IsNumber,
+} from 'class-validator';
+import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
+import { ChainId, Role } from '@human-protocol/sdk';
+
+export class LeaderDto {
+ @ApiProperty({ example: ChainId.POLYGON_AMOY })
+ @IsEnum(ChainId)
+ public chainId: ChainId;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ public address: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @IsString()
+ public balance: string;
+
+ @ApiProperty({ example: Role.JobLauncher })
+ @ApiPropertyOptional()
+ @IsOptional()
+ @IsString()
+ @Expose()
+ public role?: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @Transform(({ value }) => value.toString())
+ @IsString()
+ @Expose()
+ public amountStaked: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @Transform(({ value }) => value.toString())
+ @IsString()
+ @Expose()
+ public amountAllocated: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @Transform(({ value }) => value.toString())
+ @IsString()
+ @Expose()
+ public amountLocked: string;
+
+ @ApiProperty({ example: 1720526098 })
+ @IsNumber()
+ @Expose()
+ public lockedUntilTimestamp: number;
+
+ @ApiProperty({ example: 1 })
+ @Transform(({ value }) => Number(value))
+ @IsNumber()
+ @Expose()
+ public reputation: number;
+
+ @ApiProperty({ example: 3 })
+ @Transform(({ value }) => Number(value))
+ @IsNumber()
+ @Expose()
+ public fee: number;
+
+ @ApiProperty({ example: ['Bounding Box', 'Skeletons'] })
+ @ApiPropertyOptional()
+ @IsOptional()
+ @IsArray()
+ @Expose()
+ public jobTypes?: string[];
+
+ @ApiProperty({ example: 'https://example.test' })
+ @ApiPropertyOptional()
+ @IsOptional()
+ @IsUrl()
+ @Expose()
+ public url?: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @Transform(({ value }) => value.toString())
+ @IsString()
+ @Expose()
+ public reward: string;
+
+ @ApiProperty({ example: 1 })
+ @IsNumber()
+ @Expose()
+ public amountJobsLaunched: number;
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/dto/transaction.dto.ts b/packages/apps/dashboard/server/src/modules/details/dto/transaction.dto.ts
new file mode 100644
index 0000000000..38aebca3c3
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/dto/transaction.dto.ts
@@ -0,0 +1,40 @@
+import { Expose, Transform } from 'class-transformer';
+import { IsNumber, IsString } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class TransactionPaginationDto {
+ @ApiProperty({ example: 12345 })
+ @Transform(({ value }) => Number(value))
+ @IsNumber()
+ @Expose()
+ public block: number;
+
+ @ApiProperty({
+ example:
+ '0x020efc94ef6d9d7aa9a4886cc9e1659f4f2b63557133c29d51f387bcb0c4afd7',
+ })
+ @IsString()
+ @Expose()
+ public txHash: string;
+
+ @ApiProperty({ example: '0xad1F7e45D83624A0c628F1B03477c6E129EddB78' })
+ @IsString()
+ @Expose()
+ public from: string;
+
+ @ApiProperty({ example: '0xad1F7e45D83624A0c628F1B03477c6E129EddB78' })
+ @IsString()
+ @Expose()
+ public to: string;
+
+ @ApiProperty({ example: '0.123' })
+ @Transform(({ value }) => value.toString())
+ @IsString()
+ @Expose()
+ public value: string;
+
+ @ApiProperty({ example: 'Transfer' })
+ @IsString()
+ @Expose()
+ public method: string;
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/dto/validation/role-validation.ts b/packages/apps/dashboard/server/src/modules/details/dto/validation/role-validation.ts
new file mode 100644
index 0000000000..2079d8029a
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/dto/validation/role-validation.ts
@@ -0,0 +1,29 @@
+import {
+ registerDecorator,
+ ValidatorConstraint,
+ ValidatorConstraintInterface,
+} from 'class-validator';
+import { Role } from '@human-protocol/sdk';
+
+@ValidatorConstraint({ async: false })
+export class IsValidRoleConstraint implements ValidatorConstraintInterface {
+ validate(role: string) {
+ return Object.values(Role).includes(role);
+ }
+
+ defaultMessage() {
+ return `Role must be one of the following values: ${Object.values(
+ Role,
+ ).join(', ')}`;
+ }
+}
+
+export function IsRoleValid() {
+ return function (object: object, propertyName: string) {
+ registerDecorator({
+ target: object.constructor,
+ propertyName: propertyName,
+ validator: IsValidRoleConstraint,
+ });
+ };
+}
diff --git a/packages/apps/dashboard/server/src/modules/details/dto/wallet.dto.ts b/packages/apps/dashboard/server/src/modules/details/dto/wallet.dto.ts
new file mode 100644
index 0000000000..5a49dac3f3
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/details/dto/wallet.dto.ts
@@ -0,0 +1,17 @@
+import { IsEnum, IsString } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+import { ChainId } from '@human-protocol/sdk';
+
+export class WalletDto {
+ @ApiProperty({ example: ChainId.POLYGON_AMOY })
+ @IsEnum(ChainId)
+ public chainId: ChainId;
+
+ @ApiProperty({ example: '0xb794f5ea0ba39494ce839613fffba74279579268' })
+ @IsString()
+ public address: string;
+
+ @ApiProperty({ example: '0.07007358932392' })
+ @IsString()
+ public balance: string;
+}
diff --git a/packages/apps/dashboard/server/src/modules/redis/redis.module.ts b/packages/apps/dashboard/server/src/modules/redis/redis.module.ts
new file mode 100644
index 0000000000..28a5cb8435
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/redis/redis.module.ts
@@ -0,0 +1,9 @@
+import { RedisService } from './redis.service';
+import { Module } from '@nestjs/common';
+
+@Module({
+ imports: [],
+ providers: [RedisService],
+ exports: [RedisService],
+})
+export class RedisModule {}
diff --git a/packages/apps/dashboard/server/src/modules/redis/redis.service.ts b/packages/apps/dashboard/server/src/modules/redis/redis.service.ts
new file mode 100644
index 0000000000..7219b9345f
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/redis/redis.service.ts
@@ -0,0 +1,29 @@
+import { Inject, Injectable, Logger } from '@nestjs/common';
+import { Cache, CACHE_MANAGER } from '@nestjs/cache-manager';
+
+import { RedisConfigService } from '../../common/config/redis-config.service';
+
+@Injectable()
+export class RedisService {
+ private readonly logger = new Logger(RedisService.name);
+ constructor(
+ @Inject(CACHE_MANAGER) private cacheManager: Cache,
+ private readonly redisConfigService: RedisConfigService,
+ ) {}
+
+ async getHmtPrice(): Promise {
+ const cachedHmtPrice: number | undefined = await this.cacheManager.get(
+ this.redisConfigService.hmtPriceCacheKey,
+ );
+ return cachedHmtPrice;
+ }
+
+ async setHmtPrice(hmtPrice: number): Promise {
+ this.logger.log(`Setting a new HMT price: ${hmtPrice}`);
+ await this.cacheManager.set(
+ this.redisConfigService.hmtPriceCacheKey,
+ hmtPrice,
+ { ttl: this.redisConfigService.cacheHmtPriceTTL } as any,
+ );
+ }
+}
diff --git a/packages/apps/dashboard/server/src/modules/stats/dto/hmt-price.dto.ts b/packages/apps/dashboard/server/src/modules/stats/dto/hmt-price.dto.ts
new file mode 100644
index 0000000000..47f292ad0a
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/stats/dto/hmt-price.dto.ts
@@ -0,0 +1,8 @@
+import { IsNumber } from 'class-validator';
+import { ApiProperty } from '@nestjs/swagger';
+
+export class HmtPriceDto {
+ @ApiProperty({ example: 0.123 })
+ @IsNumber()
+ public hmtPrice: number;
+}
diff --git a/packages/apps/dashboard/server/src/modules/stats/stats.controller.ts b/packages/apps/dashboard/server/src/modules/stats/stats.controller.ts
new file mode 100644
index 0000000000..2170c8330c
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/stats/stats.controller.ts
@@ -0,0 +1,26 @@
+import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
+import { Controller, Get, HttpCode } from '@nestjs/common';
+import { StatsService } from './stats.service';
+import { HmtPriceDto } from './dto/hmt-price.dto';
+
+@ApiTags('Stats')
+@Controller('/stats')
+export class StatsController {
+ constructor(private readonly statsService: StatsService) {}
+
+ @Get('/hmt-price')
+ @HttpCode(200)
+ @ApiOperation({
+ summary: 'Get current HMT price',
+ description: 'Endpoint to return a current HMT price.',
+ })
+ @ApiResponse({
+ status: 200,
+ description: 'Price retrieved successfully',
+ type: HmtPriceDto,
+ })
+ public async hmtPrice(): Promise {
+ const hmtPrice = await this.statsService.hmtPrice();
+ return { hmtPrice };
+ }
+}
diff --git a/packages/apps/dashboard/server/src/modules/stats/stats.module.ts b/packages/apps/dashboard/server/src/modules/stats/stats.module.ts
new file mode 100644
index 0000000000..8924c2b170
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/stats/stats.module.ts
@@ -0,0 +1,13 @@
+import { HttpModule } from '@nestjs/axios';
+import { Module } from '@nestjs/common';
+
+import { RedisService } from '../redis/redis.service';
+import { StatsService } from './stats.service';
+import { StatsController } from './stats.controller';
+
+@Module({
+ imports: [HttpModule],
+ controllers: [StatsController],
+ providers: [RedisService, StatsService],
+})
+export class StatsModule {}
diff --git a/packages/apps/dashboard/server/src/modules/stats/stats.service.ts b/packages/apps/dashboard/server/src/modules/stats/stats.service.ts
new file mode 100644
index 0000000000..bf2af86b4e
--- /dev/null
+++ b/packages/apps/dashboard/server/src/modules/stats/stats.service.ts
@@ -0,0 +1,36 @@
+import { Injectable, Logger } from '@nestjs/common';
+import { HttpService } from '@nestjs/axios';
+import { lastValueFrom } from 'rxjs';
+
+import { EnvironmentConfigService } from '../../common/config/env-config.service';
+import { RedisService } from '../redis/redis.service';
+
+@Injectable()
+export class StatsService {
+ private readonly logger = new Logger(StatsService.name);
+ constructor(
+ private readonly envConfigService: EnvironmentConfigService,
+ private readonly httpService: HttpService,
+ private readonly redisService: RedisService,
+ ) {}
+ public async hmtPrice(): Promise {
+ const cachedHmtPrice = await this.redisService.getHmtPrice();
+ if (cachedHmtPrice) {
+ return cachedHmtPrice;
+ }
+
+ const { data } = await lastValueFrom(
+ this.httpService.get(this.envConfigService.hmtPriceSource, {
+ headers: {
+ 'x-cg-demo-api-key': this.envConfigService.hmtPriceSourceApiKey,
+ },
+ }),
+ );
+ const hmtPrice =
+ data[this.envConfigService.hmtPriceFromKey][
+ this.envConfigService.hmtPriceToKey
+ ];
+ await this.redisService.setHmtPrice(hmtPrice);
+ return hmtPrice;
+ }
+}
diff --git a/packages/apps/dashboard/server/tsconfig.build.json b/packages/apps/dashboard/server/tsconfig.build.json
new file mode 100644
index 0000000000..64f86c6bd2
--- /dev/null
+++ b/packages/apps/dashboard/server/tsconfig.build.json
@@ -0,0 +1,4 @@
+{
+ "extends": "./tsconfig.json",
+ "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
+}
diff --git a/packages/apps/dashboard/server/tsconfig.json b/packages/apps/dashboard/server/tsconfig.json
new file mode 100644
index 0000000000..adb614cab7
--- /dev/null
+++ b/packages/apps/dashboard/server/tsconfig.json
@@ -0,0 +1,21 @@
+{
+ "compilerOptions": {
+ "module": "commonjs",
+ "declaration": true,
+ "removeComments": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "allowSyntheticDefaultImports": true,
+ "target": "es2017",
+ "sourceMap": true,
+ "outDir": "./dist",
+ "baseUrl": "./",
+ "incremental": true,
+ "skipLibCheck": true,
+ "strictNullChecks": false,
+ "noImplicitAny": false,
+ "strictBindCallApply": false,
+ "forceConsistentCasingInFileNames": false,
+ "noFallthroughCasesInSwitch": false
+ }
+}
diff --git a/packages/apps/dashboard/ui/README.md b/packages/apps/dashboard/ui/README.md
index 9fabd03730..6ce33d39b8 100644
--- a/packages/apps/dashboard/ui/README.md
+++ b/packages/apps/dashboard/ui/README.md
@@ -1,50 +1,62 @@
-# HUMAN Escrow Factory Dashboard
+
+
+
-This is a readonly dashboard of the [Escrow Factory](https://github.com/humanprotocol/hmt-escrow/blob/master/contracts/EscrowFactory.sol) contract
+[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
+[circleci-url]: https://circleci.com/gh/nestjs/nest
-Escrow Factory is used for grouping Escrows in the blockchain. Everything is happening inside Polygon Mainnet. Other networks will be added later
+HUMAN Dashboard
+ HUMAN Dashboard is a comprehensive interface that provides users with detailed insights of the HUMAN Protocol ecosystem. This dashboard is designed to facilitate the tracking of HMT token transactions, escrows, payouts, staking and to provide up-to-date information about available oracles and their reputations
-## Available Scripts
+
+
+
+
+
-In the project directory, you can run:
+## ✨ Demo
-### `yarn start`
+First, let's install the dependencies, `yarn` is used as a package manager:
-Runs the app in the development mode.\
-Open [http://localhost:3002](http://localhost:3002) to view it in your browser.
+```bash
+$ yarn install
+```
-The page will reload when you make changes.\
-You may also see any lint errors in the console.
+The application needs access to environment variables in order to work correctly, for this, create one of the `.env.` files, depending on the state of your environment:
-### `yarn run build`
+```bash
+$ export NODE_ENV=development
+```
-Before building you need to set environment variable in `.env`:
+Use the `.env.example` file as an example to create a configuration file with certain environment variables:
+```bash
+$ cp .env.example .env.development
```
-VITE_APP_NFT_STORAGE_API=
-VITE_APP_FAUCET_SERVER_URL=
-VITE_APP_WALLETCONNECT_PROJECT_ID=
-```
-Builds the app for production to the `dist` folder.\
-It correctly bundles React in production mode and optimizes the build for the best performance.
+## 🚀 Usage
+
+### Running the app
-The build is minified and the filenames include the hashes.
+```bash
+$ yarn run start
+```
-### `yarn test/ run lint`
+### Testing the app
-# Branching
-[GitFlow convention](https://www.gitkraken.com/learn/git/git-flow) is to be followed (and feature PRs should target `develop` branch rather than `master`)
+```bash
+# unit tests
+$ yarn run test
+```
-# Deployment
+# Branching
-[Internal CI CD documentation](https://www.notion.so/human-protocol/Escrow-Dashboard-47d26b3be14f4ad395e2fcd4a168d77f)
+[GitFlow convention](https://www.gitkraken.com/learn/git/git-flow) is to be followed (and feature PRs should target `develop` branch rather than `main`)
## Deployment Endpoints
-`develop` branch → staging: http://ec2-18-219-139-195.us-east-2.compute.amazonaws.com/
+`main` branch → production: https://dashboard.humanprotocol.org/
-`master` branch → production: https://dashboard.humanprotocol.org/
+## License
-# Tests
-Feel free to add your own automated tests following GiHub Actions documentation
+This project is licensed under the MIT License. See the [LICENSE](https://github.com/humanprotocol/human-protocol/blob/main/LICENSE) file for details.
diff --git a/packages/apps/dashboard/ui/package.json b/packages/apps/dashboard/ui/package.json
index abedcfca56..6eecc24256 100644
--- a/packages/apps/dashboard/ui/package.json
+++ b/packages/apps/dashboard/ui/package.json
@@ -9,11 +9,11 @@
"@emotion/styled": "^11.10.5",
"@human-protocol/sdk": "*",
"@mui/icons-material": "^5.15.11",
- "@mui/material": "^5.15.18",
+ "@mui/material": "^5.15.19",
"@reduxjs/toolkit": "^1.9.0",
"@tanstack/query-sync-storage-persister": "^5.38.0",
- "@tanstack/react-query": "^5.35.1",
- "@tanstack/react-query-persist-client": "^5.35.4",
+ "@tanstack/react-query": "^5.49.2",
+ "@tanstack/react-query-persist-client": "^5.51.11",
"axios": "^1.2.3",
"bignumber.js": "^9.1.0",
"copy-to-clipboard": "^3.3.3",
@@ -23,7 +23,7 @@
"file-saver": "^2.0.5",
"graphql": "^16.6.0",
"jszip": "^3.10.1",
- "nft.storage": "^7.0.0",
+ "nft.storage": "^7.2.0",
"numeral": "^2.0.6",
"openpgp": "^5.11.1",
"react": "^18.2.0",
@@ -38,11 +38,11 @@
"swr": "^2.2.4",
"viem": "2.x",
"wagmi": "^2.8.5",
- "web-vitals": "^3.5.2"
+ "web-vitals": "^4.2.2"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.4.2",
- "@testing-library/react": "^14.2.1",
+ "@testing-library/react": "^15.0.7",
"@types/crypto-js": "^4.1.2",
"@types/file-saver": "^2.0.5",
"@types/glob": "^8.1.0",
@@ -52,21 +52,18 @@
"@types/react-gtm-module": "^2.0.3",
"@types/react-test-renderer": "^18.0.0",
"@vitejs/plugin-react": "^4.2.1",
- "crypto-js": "^4.2.0",
"dotenv": "^16.3.2",
"eslint-config-react-app": "^7.0.1",
"eslint-import-resolver-typescript": "^3.5.2",
"eslint-plugin-import": "^2.29.0",
- "eslint-plugin-react": "^7.31.10",
+ "eslint-plugin-react": "^7.34.3",
"eslint-plugin-react-hooks": "^4.6.0",
"happy-dom": "^12.9.1",
"identity-obj-proxy": "^3.0.0",
"jsdom": "^24.1.0",
- "merkletreejs": "^0.3.11",
"resize-observer-polyfill": "^1.5.1",
- "sinon": "^17.0.1",
"vite": "^5.0.12",
- "vite-plugin-node-polyfills": "^0.19.0",
+ "vite-plugin-node-polyfills": "^0.22.0",
"vitest": "^1.6.0"
},
"scripts": {
@@ -100,7 +97,6 @@
]
},
"resolutions": {
- "ejs": "^3.1.8",
"gluegun": "^5.0.0",
"mocha": "^10.0.0",
"node-fetch": "^2.6.7",
diff --git a/packages/apps/dashboard/ui/scripts/__tests__/generateMerkleTree.test.ts b/packages/apps/dashboard/ui/scripts/__tests__/generateMerkleTree.test.ts
deleted file mode 100644
index b7a0a09316..0000000000
--- a/packages/apps/dashboard/ui/scripts/__tests__/generateMerkleTree.test.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-import * as path from 'path';
-import { NFTStorage } from 'nft.storage';
-import { stub, restore } from 'sinon';
-import { test, assert, vi } from 'vitest';
-import generateMerkleTree from '../generateMerkleTree';
-const mockToken = 'test-token';
-
-vi.mock('fs', () => ({
- readFileSync: vi.fn().mockReturnValue('test-file-content'),
-}));
-
-vi.mock('glob', () => ({
- sync: vi.fn().mockImplementation(() => ['test.js', 'test2.js']),
-}));
-
-test('generateMerkleTree should return a valid Merkle tree JSON', async () => {
- const tmpDistAssetsPath = path.join(__dirname, 'tmp-dist-assets');
-
- // Mock NFTStorage.storeBlob method
- const fakeCid = 'bafybeih42y6g7zkr76j6ax7z6wjc5d56xazsrtxzp6f7j6fsk67djnppmq';
- stub(NFTStorage.prototype, 'storeBlob').resolves(fakeCid);
-
- const origin = 'https://example.com';
-
- const merkleTreeJson = await generateMerkleTree(
- origin,
- mockToken,
- tmpDistAssetsPath
- );
- const merkleTreeData = JSON.parse(merkleTreeJson);
-
- // Cleanup and restore the actual file system and NFTStorage.storeBlob method
- restore();
-
- // Assertions
- assert(
- merkleTreeData.hasOwnProperty('version'),
- 'Merkle tree JSON should have a "version" property'
- );
- assert(
- merkleTreeData.version === fakeCid,
- 'Merkle tree JSON "version" should match the fake CID'
- );
- assert(
- merkleTreeData.hasOwnProperty('root'),
- 'Merkle tree JSON should have a "root" property'
- );
- assert(
- merkleTreeData.hasOwnProperty('leaves'),
- 'Merkle tree JSON should have a "leaves" property'
- );
- assert(
- merkleTreeData.root.startsWith('0x'),
- 'Merkle tree root hash should start with "0x"'
- );
- assert(
- merkleTreeData.leaves.length > 0,
- 'Merkle tree leaves should not be empty'
- );
- assert(
- merkleTreeData.leaves.every((leaf) => leaf.startsWith('0x')),
- 'Each Merkle tree leaf hash should start with "0x"'
- );
-});
diff --git a/packages/apps/dashboard/ui/scripts/generateMerkleTree.ts b/packages/apps/dashboard/ui/scripts/generateMerkleTree.ts
deleted file mode 100644
index 473684243c..0000000000
--- a/packages/apps/dashboard/ui/scripts/generateMerkleTree.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-import * as fs from 'node:fs';
-import * as path from 'path';
-import { SHA256 } from 'crypto-js';
-import * as glob from 'glob';
-import { MerkleTree } from 'merkletreejs';
-import { NFTStorage } from 'nft.storage';
-
-export default async function generateMerkleTree(
- origin: string,
- token: string,
- buildPath?: string
-): Promise {
- if (!buildPath) {
- buildPath = path.join(__dirname, '../dist/assets');
- }
-
- const allFiles = glob.sync('**/*.js', { cwd: buildPath });
- const NFT_STORAGE_CLIENT = new NFTStorage({
- token,
- });
- const fileHashes = allFiles.map((file) => {
- const filePath = path.join(buildPath, file);
- const fileContent = fs.readFileSync(filePath, 'utf-8');
- return SHA256(fileContent).toString();
- });
-
- const merkleTree = new MerkleTree(fileHashes, SHA256);
- const merkleRoot = '0x' + merkleTree.getRoot().toString('hex');
-
- // Add the '0x' prefix to each leaf
- const leaves = merkleTree
- .getLeaves()
- .map((leaf) => '0x' + leaf.toString('hex'));
-
- const someData = new Blob([
- JSON.stringify({
- origin,
- root_hash: merkleRoot,
- published_date: Date.now(),
- }) as string,
- ]);
- const cid = await NFT_STORAGE_CLIENT.storeBlob(someData);
-
- const merkleTreeJson = JSON.stringify({
- version: cid,
- root: merkleRoot,
- leaves: leaves,
- });
-
- return merkleTreeJson;
-}
diff --git a/packages/apps/dashboard/ui/src/components/Icons/TwitterIcon.tsx b/packages/apps/dashboard/ui/src/components/Icons/TwitterIcon.tsx
deleted file mode 100644
index 7d32989634..0000000000
--- a/packages/apps/dashboard/ui/src/components/Icons/TwitterIcon.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
-import { FC } from 'react';
-
-export const TwitterIcon: FC = (props) => {
- return (
-
-
-
- );
-};
diff --git a/packages/apps/dashboard/ui/src/components/Icons/XIcon.tsx b/packages/apps/dashboard/ui/src/components/Icons/XIcon.tsx
new file mode 100644
index 0000000000..8851612a67
--- /dev/null
+++ b/packages/apps/dashboard/ui/src/components/Icons/XIcon.tsx
@@ -0,0 +1,19 @@
+import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
+import { FC } from 'react';
+
+export const XIcon: FC = (props) => {
+ return (
+
+
+
+ );
+};
diff --git a/packages/apps/dashboard/ui/src/components/Icons/index.ts b/packages/apps/dashboard/ui/src/components/Icons/index.ts
index 189923a4f0..b47142a4eb 100644
--- a/packages/apps/dashboard/ui/src/components/Icons/index.ts
+++ b/packages/apps/dashboard/ui/src/components/Icons/index.ts
@@ -16,4 +16,4 @@ export { MoonbeamIcon } from './MoonbeamIcon';
export { OpenInNewIcon } from './OpenInNewIcon';
export { PolygonIcon } from './PolygonIcon';
export { TelegramIcon } from './TelegramIcon';
-export { TwitterIcon } from './TwitterIcon';
+export { XIcon } from './XIcon';
diff --git a/packages/apps/dashboard/ui/src/components/SocialIcons/SocialIcons.tsx b/packages/apps/dashboard/ui/src/components/SocialIcons/SocialIcons.tsx
index 7e77adf45f..aa74d8f3ae 100644
--- a/packages/apps/dashboard/ui/src/components/SocialIcons/SocialIcons.tsx
+++ b/packages/apps/dashboard/ui/src/components/SocialIcons/SocialIcons.tsx
@@ -1,7 +1,7 @@
import { Box, Link } from '@mui/material';
import { FC } from 'react';
-import { DiscordIcon, GithubIcon, LinkedinIcon, TwitterIcon } from '../Icons';
+import { DiscordIcon, GithubIcon, LinkedinIcon, XIcon } from '../Icons';
type SocialIconProps = {
direction?: 'row' | 'row-reverse' | 'column' | 'column-reverse';
@@ -28,7 +28,7 @@ export const SocialIcons: FC = ({ direction = 'row' }) => (
target="_blank"
sx={{ m: direction === 'row' ? '0px 15px' : '15px 0px' }}
>
-
+
('leader/fetchLeaderEscrowsAsync', async ({ chainId, address }) => {
const launchedEscrows = await EscrowUtils.getEscrows({
- networks: [chainId],
+ chainId: chainId,
launcher: address,
});
diff --git a/packages/apps/dashboard/ui/vite.config.ts b/packages/apps/dashboard/ui/vite.config.ts
index 8fa394d12c..7664eb91c1 100644
--- a/packages/apps/dashboard/ui/vite.config.ts
+++ b/packages/apps/dashboard/ui/vite.config.ts
@@ -1,12 +1,10 @@
///
///
-import * as fs from 'fs';
import path from 'path';
import react from '@vitejs/plugin-react';
import * as dotenv from 'dotenv';
import { defineConfig } from 'vite';
import { nodePolyfills } from 'vite-plugin-node-polyfills';
-import generateMerkleTree from './scripts/generateMerkleTree';
dotenv.config();
@@ -19,26 +17,6 @@ export default defineConfig(({ mode }) => {
// Whether to polyfill `node:` protocol imports.
protocolImports: true,
}),
- {
- name: 'generate-merkle-tree',
- apply: 'build',
- async writeBundle() {
- const merkleTreeJson = await generateMerkleTree(
- mode === 'development'
- ? 'localhost'
- : 'dashboard.humanprotocol.org',
- process.env.VITE_APP_NFT_STORAGE_API as string
- );
-
- const indexPath = path.resolve(__dirname, './dist/index.html');
- const indexContent = fs.readFileSync(indexPath, 'utf-8');
- const newIndexContent = indexContent.replace(
- '',
- ``
- );
- fs.writeFileSync(indexPath, newIndexContent);
- },
- },
],
worker: {
plugins: () => react(),
diff --git a/packages/apps/fortune/exchange-oracle/client/.env.example b/packages/apps/fortune/exchange-oracle/client/.env.example
new file mode 100644
index 0000000000..da2c159e02
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/.env.example
@@ -0,0 +1,11 @@
+VITE_APP_EXCHANGE_ORACLE_SERVER_URL=
+VITE_APP_ENVIRONMENT=testnet
+VITE_APP_RPC_URL_POLYGON=
+VITE_APP_RPC_URL_BSC=
+VITE_APP_RPC_URL_POLYGON_AMOY=
+VITE_APP_RPC_URL_GOERLI=
+VITE_APP_RPC_URL_SEPOLIA=
+VITE_APP_RPC_URL_MOONBEAM=
+VITE_APP_RPC_URL_BSC_TESTNET=
+VITE_APP_RPC_URL_LOCALHOST=http://0.0.0.0:8545/
+VITE_APP_WALLETCONNECT_PROJECT_ID=
\ No newline at end of file
diff --git a/packages/apps/fortune/exchange-oracle/client/.eslintrc.cjs b/packages/apps/fortune/exchange-oracle/client/.eslintrc.cjs
new file mode 100644
index 0000000000..dd29102b35
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/.eslintrc.cjs
@@ -0,0 +1,19 @@
+module.exports = {
+ root: true,
+ env: { browser: true, es2020: true },
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ 'plugin:react-hooks/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parser: '@typescript-eslint/parser',
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ '@typescript-eslint/no-explicit-any': 'off',
+ },
+};
diff --git a/packages/apps/fortune/exchange-oracle/client/.gitignore b/packages/apps/fortune/exchange-oracle/client/.gitignore
new file mode 100644
index 0000000000..a547bf36d8
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/.gitignore
@@ -0,0 +1,24 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
diff --git a/packages/apps/fortune/exchange-oracle/client/README.md b/packages/apps/fortune/exchange-oracle/client/README.md
new file mode 100644
index 0000000000..0d6babeddb
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/README.md
@@ -0,0 +1,30 @@
+# React + TypeScript + Vite
+
+This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
+
+Currently, two official plugins are available:
+
+- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
+- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
+
+## Expanding the ESLint configuration
+
+If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
+
+- Configure the top-level `parserOptions` property like this:
+
+```js
+export default {
+ // other rules...
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ project: ['./tsconfig.json', './tsconfig.node.json'],
+ tsconfigRootDir: __dirname,
+ },
+}
+```
+
+- Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked`
+- Optionally add `plugin:@typescript-eslint/stylistic-type-checked`
+- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and add `plugin:react/recommended` & `plugin:react/jsx-runtime` to the `extends` list
diff --git a/packages/apps/fortune/exchange-oracle/client/index.html b/packages/apps/fortune/exchange-oracle/client/index.html
new file mode 100644
index 0000000000..64790de800
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/index.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Human Protocol Exchange Oracle
+
+
+
+
+
+
diff --git a/packages/apps/fortune/exchange-oracle/client/package.json b/packages/apps/fortune/exchange-oracle/client/package.json
new file mode 100644
index 0000000000..677822e2ca
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/package.json
@@ -0,0 +1,61 @@
+{
+ "name": "@human-protocol/fortune-exchange-oracle-client",
+ "version": "1.0.0",
+ "description": "Job Launcher Client",
+ "scripts": {
+ "lint": "eslint \"**/*.{ts,tsx}\"",
+ "start": "vite --port 3006",
+ "build": "vite build",
+ "preview": "vite preview",
+ "start:prod": "serve -s dist",
+ "test": "vitest run -u",
+ "format:prettier": "prettier --write \"**/*.{ts,tsx,js,jsx}\"",
+ "format:lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"",
+ "format": "yarn format:prettier && yarn format:lint"
+ },
+ "browserslist": {
+ "production": [
+ ">0.2%",
+ "not dead",
+ "not op_mini all"
+ ],
+ "development": [
+ "last 1 chrome version",
+ "last 1 firefox version",
+ "last 1 safari version"
+ ]
+ },
+ "dependencies": {
+ "@human-protocol/sdk": "*",
+ "@mui/material": "^5.16.0",
+ "@tanstack/query-sync-storage-persister": "^5.38.0",
+ "@tanstack/react-query": "^5.49.2",
+ "@tanstack/react-query-persist-client": "^5.51.11",
+ "axios": "^1.7.2",
+ "ethers": "^6.13.1",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "react-router-dom": "^6.24.1",
+ "vite-plugin-node-polyfills": "^0.22.0",
+ "wagmi": "^2.10.10"
+ },
+ "devDependencies": {
+ "@types/react": "^18.3.3",
+ "@types/react-dom": "^18.3.0",
+ "@types/react-router-dom": "^5.3.3",
+ "@typescript-eslint/eslint-plugin": "^7.13.1",
+ "@typescript-eslint/parser": "^7.13.1",
+ "@vitejs/plugin-react": "^4.3.1",
+ "eslint": "^8.57.0",
+ "eslint-plugin-react-hooks": "^4.6.2",
+ "eslint-plugin-react-refresh": "^0.4.7",
+ "typescript": "^5.2.2",
+ "vite": "^5.3.1"
+ },
+ "lint-staged": {
+ "*.{ts,tsx}": [
+ "prettier --write",
+ "eslint --fix"
+ ]
+ }
+}
diff --git a/packages/apps/fortune/exchange-oracle/client/public/favicon.ico b/packages/apps/fortune/exchange-oracle/client/public/favicon.ico
new file mode 100644
index 0000000000..56bf7a58b9
Binary files /dev/null and b/packages/apps/fortune/exchange-oracle/client/public/favicon.ico differ
diff --git a/packages/apps/fortune/exchange-oracle/client/public/manifest.json b/packages/apps/fortune/exchange-oracle/client/public/manifest.json
new file mode 100644
index 0000000000..1f2f141faf
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/public/manifest.json
@@ -0,0 +1,15 @@
+{
+ "short_name": "React App",
+ "name": "Create React App Sample",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/packages/apps/fortune/exchange-oracle/client/public/vite.svg b/packages/apps/fortune/exchange-oracle/client/public/vite.svg
new file mode 100644
index 0000000000..e7b8dfb1b2
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/public/vite.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/apps/fortune/exchange-oracle/client/src/App.tsx b/packages/apps/fortune/exchange-oracle/client/src/App.tsx
new file mode 100644
index 0000000000..5794d28ac1
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/App.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { Route, Routes, Navigate } from 'react-router-dom';
+import Solution from './pages/Solution';
+import Home from './pages/Home';
+
+const App: React.FC = () => {
+ return (
+
+ } />
+ } />
+ } />
+
+ );
+};
+
+export default App;
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/bag.png b/packages/apps/fortune/exchange-oracle/client/src/assets/bag.png
new file mode 100644
index 0000000000..9145a460d8
Binary files /dev/null and b/packages/apps/fortune/exchange-oracle/client/src/assets/bag.png differ
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/coinbase.svg b/packages/apps/fortune/exchange-oracle/client/src/assets/coinbase.svg
new file mode 100644
index 0000000000..8e98d89e52
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/assets/coinbase.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/fund-crypto.png b/packages/apps/fortune/exchange-oracle/client/src/assets/fund-crypto.png
new file mode 100644
index 0000000000..d7676f75a0
Binary files /dev/null and b/packages/apps/fortune/exchange-oracle/client/src/assets/fund-crypto.png differ
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/human.png b/packages/apps/fortune/exchange-oracle/client/src/assets/human.png
new file mode 100644
index 0000000000..694e88c066
Binary files /dev/null and b/packages/apps/fortune/exchange-oracle/client/src/assets/human.png differ
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/logo.svg b/packages/apps/fortune/exchange-oracle/client/src/assets/logo.svg
new file mode 100644
index 0000000000..d673726b04
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/assets/logo.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/metamask.svg b/packages/apps/fortune/exchange-oracle/client/src/assets/metamask.svg
new file mode 100644
index 0000000000..f893c15924
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/assets/metamask.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/react.svg b/packages/apps/fortune/exchange-oracle/client/src/assets/react.svg
new file mode 100644
index 0000000000..6c87de9bb3
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/assets/react.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/user.png b/packages/apps/fortune/exchange-oracle/client/src/assets/user.png
new file mode 100644
index 0000000000..ca40b9c906
Binary files /dev/null and b/packages/apps/fortune/exchange-oracle/client/src/assets/user.png differ
diff --git a/packages/apps/fortune/exchange-oracle/client/src/assets/walletconnect.svg b/packages/apps/fortune/exchange-oracle/client/src/assets/walletconnect.svg
new file mode 100644
index 0000000000..3ef58a4155
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/assets/walletconnect.svg
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/fortune/exchange-oracle/client/src/components/Headers/DefaultHeader.tsx b/packages/apps/fortune/exchange-oracle/client/src/components/Headers/DefaultHeader.tsx
new file mode 100644
index 0000000000..c494bec374
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/components/Headers/DefaultHeader.tsx
@@ -0,0 +1,38 @@
+import { AppBar, Box, Link as MuiLink, Toolbar } from '@mui/material';
+import React from 'react';
+import { Link } from 'react-router-dom';
+import logoImg from '../../assets/logo.svg';
+
+export function DefaultHeader() {
+ return (
+
+
+
+
+
+
+
+ Dashboard
+
+
+ HUMAN Website
+
+
+
+
+ );
+}
diff --git a/packages/apps/fortune/exchange-oracle/client/src/components/SolutionForm/index.tsx b/packages/apps/fortune/exchange-oracle/client/src/components/SolutionForm/index.tsx
new file mode 100644
index 0000000000..5bfe8e4197
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/components/SolutionForm/index.tsx
@@ -0,0 +1,82 @@
+import { Box, Button, Grid, TextField, Typography } from '@mui/material';
+import { useState } from 'react';
+import { useParams } from 'react-router-dom';
+import { useSnackbar } from '../../providers/SnackProvider';
+import { useWalletClient } from 'wagmi';
+import * as jobService from '../../services/job';
+
+const SolutionForm: React.FC = () => {
+ const { assignmentId } = useParams<{ assignmentId: string }>();
+
+ const { data: signer } = useWalletClient();
+ const [solution, setSolution] = useState('');
+ const { showError, openSnackbar } = useSnackbar();
+
+ const handleSubmit = async () => {
+ const message = {
+ solution,
+ assignment_id: assignmentId,
+ };
+
+ try {
+ await jobService.solveJob(signer, message);
+
+ openSnackbar('Solution sent successfully', 'success');
+ } catch (error) {
+ showError(error);
+ }
+ };
+
+ return (
+
+
+
+
+
+ Submit Your Solution
+
+
+
+ setSolution(e.target.value)}
+ sx={{ mb: 3, width: '300px' }}
+ />
+
+
+ Submit
+
+
+
+
+
+ );
+};
+
+export default SolutionForm;
diff --git a/packages/apps/fortune/exchange-oracle/client/src/components/Wallet/FundingMethod.tsx b/packages/apps/fortune/exchange-oracle/client/src/components/Wallet/FundingMethod.tsx
new file mode 100644
index 0000000000..3db204f353
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/components/Wallet/FundingMethod.tsx
@@ -0,0 +1,84 @@
+import { Box, Button, Grid, Typography } from '@mui/material';
+import { useEffect, useState } from 'react';
+import { useAccount } from 'wagmi';
+import fundCryptoImg from '../../assets/fund-crypto.png';
+import WalletModal from './WalletModal';
+import SolutionForm from '../SolutionForm';
+
+export const FundingMethod = () => {
+ const [walletModalOpen, setWalletModalOpen] = useState(false);
+ const { isConnected } = useAccount();
+
+ const handleClickCrypto = () => {
+ if (!isConnected) {
+ setWalletModalOpen(true);
+ }
+ };
+
+ useEffect(() => {
+ if (isConnected && walletModalOpen) {
+ setWalletModalOpen(false);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [isConnected]);
+
+ return (
+ <>
+ {isConnected ? (
+ // Mostrar el formulario de solución si está conectado
+ ) : (
+
+
+
+
+
+
+ Click to connect your wallet
+
+
+ Crypto
+
+
+
+
+
+ )}
+ setWalletModalOpen(false)}
+ />
+ >
+ );
+};
diff --git a/packages/apps/fortune/exchange-oracle/client/src/components/Wallet/WalletModal.tsx b/packages/apps/fortune/exchange-oracle/client/src/components/Wallet/WalletModal.tsx
new file mode 100644
index 0000000000..f3d32161a0
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/components/Wallet/WalletModal.tsx
@@ -0,0 +1,111 @@
+import CloseIcon from '@mui/icons-material/Close';
+import {
+ Box,
+ Button,
+ Dialog,
+ IconButton,
+ Typography,
+ useTheme,
+} from '@mui/material';
+import { useConnect } from 'wagmi';
+import coinbaseSvg from '../../assets/coinbase.svg';
+import metaMaskSvg from '../../assets/metamask.svg';
+import walletConnectSvg from '../../assets/walletconnect.svg';
+
+const WALLET_ICONS: Record = {
+ metaMask: metaMaskSvg,
+ coinbaseWalletSDK: coinbaseSvg,
+ walletConnect: walletConnectSvg,
+};
+
+export default function WalletModal({
+ open,
+ onClose,
+}: {
+ open: boolean;
+ onClose: () => void;
+}) {
+ const { connect, connectors, error } = useConnect();
+
+ const theme = useTheme();
+
+ return (
+
+
+
+
+ Connect
+ your wallet
+
+
+ By connecting a wallet, you agree to HUMAN Protocol Terms of Service
+ and consent to its Privacy Policy.
+
+
+
+
+
+
+
+ {connectors.map((connector) => (
+ {
+ connect({ connector });
+
+ if (connector.id === 'walletConnect') {
+ onClose();
+ }
+ }}
+ >
+
+ {connector.name}
+
+ ))}
+
+
+ {error && {error.message}
}
+
+
+
+ );
+}
diff --git a/packages/apps/fortune/exchange-oracle/client/src/constants/chains.ts b/packages/apps/fortune/exchange-oracle/client/src/constants/chains.ts
new file mode 100644
index 0000000000..16fd3bf025
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/constants/chains.ts
@@ -0,0 +1,83 @@
+import { ChainId } from '@human-protocol/sdk';
+
+export const IS_MAINNET =
+ import.meta.env.VITE_APP_ENVIRONMENT.toLowerCase() === 'mainnet';
+export const IS_TESTNET = !IS_MAINNET;
+
+let initialSupportedChainIds: ChainId[];
+switch (import.meta.env.VITE_APP_ENVIRONMENT.toLowerCase()) {
+ case 'mainnet':
+ initialSupportedChainIds = [ChainId.POLYGON];
+ break;
+ case 'testnet':
+ initialSupportedChainIds = [
+ ChainId.BSC_TESTNET,
+ ChainId.POLYGON_AMOY,
+ ChainId.SEPOLIA,
+ ChainId.XLAYER_TESTNET,
+ ];
+ break;
+ case 'localhost':
+ default:
+ initialSupportedChainIds = [ChainId.LOCALHOST];
+ break;
+}
+
+export const RPC_URLS: Partial> = {
+ [ChainId.MAINNET]: import.meta.env.VITE_APP_RPC_URL_MAINNET || '',
+ [ChainId.SEPOLIA]: import.meta.env.VITE_APP_RPC_URL_SEPOLIA || '',
+ [ChainId.BSC_MAINNET]: import.meta.env.VITE_APP_RPC_URL_BSC_MAINNET || '',
+ [ChainId.BSC_TESTNET]: import.meta.env.VITE_APP_RPC_URL_BSC_TESTNET || '',
+ [ChainId.POLYGON]: import.meta.env.VITE_APP_RPC_URL_POLYGON || '',
+ [ChainId.POLYGON_AMOY]: import.meta.env.VITE_APP_RPC_URL_POLYGON_AMOY || '',
+ [ChainId.MOONBEAM]: import.meta.env.VITE_APP_RPC_URL_MOONBEAM || '',
+ [ChainId.MOONBASE_ALPHA]:
+ import.meta.env.VITE_APP_RPC_URL_MOONBASE_ALPHA || '',
+ [ChainId.AVALANCHE_TESTNET]:
+ import.meta.env.VITE_APP_RPC_URL_AVALANCHE_TESTNET || '',
+ [ChainId.AVALANCHE]: import.meta.env.VITE_APP_RPC_URL_AVALANCHE || '',
+ [ChainId.CELO_ALFAJORES]:
+ import.meta.env.VITE_APP_RPC_URL_CELO_ALFAJORES || '',
+ [ChainId.CELO]: import.meta.env.VITE_APP_RPC_URL_CELO || '',
+ [ChainId.XLAYER]: import.meta.env.VITE_APP_RPC_URL_XLAYER || '',
+ [ChainId.XLAYER_TESTNET]:
+ import.meta.env.VITE_APP_RPC_URL_XLAYER_TESTNET || '',
+ [ChainId.LOCALHOST]: 'http://127.0.0.1:8545',
+};
+
+export const SUPPORTED_CHAIN_IDS: ChainId[] = initialSupportedChainIds.filter(
+ (chainId) => Boolean(RPC_URLS[chainId])
+);
+
+// it no rpc set, throw error
+if (SUPPORTED_CHAIN_IDS.length === 0) {
+ throw new Error(
+ 'No valid RPC URL provided for the supported blockchain environment'
+ );
+}
+
+export const CHAIN_ID_BY_NAME: Record = {
+ 'Polygon Amoy': ChainId.POLYGON_AMOY,
+ 'Binance Smart Chain': ChainId.BSC_MAINNET,
+ 'Ethereum Sepolia': ChainId.SEPOLIA,
+ Localhost: ChainId.LOCALHOST,
+};
+
+export const LOCALHOST = {
+ id: 1338,
+ name: 'Localhost',
+ network: 'localhost',
+ nativeCurrency: {
+ decimals: 18,
+ name: 'Ether',
+ symbol: 'ETH',
+ },
+ rpcUrls: {
+ default: {
+ http: ['http://127.0.0.1:8545'],
+ },
+ public: {
+ http: ['http://127.0.0.1:8545'],
+ },
+ },
+};
diff --git a/packages/apps/fortune/exchange-oracle/client/src/constants/index.tsx b/packages/apps/fortune/exchange-oracle/client/src/constants/index.tsx
new file mode 100644
index 0000000000..60a4cd3b44
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/constants/index.tsx
@@ -0,0 +1 @@
+export const HUMAN_SIGNATURE_KEY = 'human-signature';
diff --git a/packages/apps/fortune/exchange-oracle/client/src/index.css b/packages/apps/fortune/exchange-oracle/client/src/index.css
new file mode 100644
index 0000000000..addebdf52a
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/index.css
@@ -0,0 +1,4 @@
+a {
+ color: #320a8d;
+ text-decoration: none;
+}
diff --git a/packages/apps/fortune/exchange-oracle/client/src/main.tsx b/packages/apps/fortune/exchange-oracle/client/src/main.tsx
new file mode 100644
index 0000000000..93cf00316e
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/main.tsx
@@ -0,0 +1,28 @@
+import CssBaseline from '@mui/material/CssBaseline';
+import { ThemeProvider } from '@mui/material/styles';
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import { BrowserRouter as Router } from 'react-router-dom';
+import App from './App';
+import SnackbarProvider from './providers/SnackProvider';
+import './index.css';
+import theme from './theme';
+import { WagmiProvider } from './providers/WagmiProvider';
+import { QueryClientProvider } from './providers/QueryClientProvider';
+
+ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/packages/apps/fortune/exchange-oracle/client/src/pages/Home/index.tsx b/packages/apps/fortune/exchange-oracle/client/src/pages/Home/index.tsx
new file mode 100644
index 0000000000..aac8077def
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/pages/Home/index.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { Box, Grid, Typography } from '@mui/material';
+import { Outlet } from 'react-router-dom';
+import bagImg from '../../assets/bag.png';
+import humanImg from '../../assets/human.png';
+import userImg from '../../assets/user.png';
+import { DefaultHeader } from '../../components/Headers/DefaultHeader';
+
+const Home: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ HUMAN
+
+ Exchange Oracle
+
+
+ Solve Jobs on Fortune.
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Home;
diff --git a/packages/apps/fortune/exchange-oracle/client/src/pages/Solution/index.tsx b/packages/apps/fortune/exchange-oracle/client/src/pages/Solution/index.tsx
new file mode 100644
index 0000000000..c30c7d2885
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/pages/Solution/index.tsx
@@ -0,0 +1,41 @@
+import React from 'react';
+import { Box, Container } from '@mui/material';
+import { useAccount } from 'wagmi';
+import { FundingMethod } from '../../components/Wallet/FundingMethod';
+import SolutionForm from '../../components/SolutionForm';
+import { DefaultHeader } from '../../components/Headers/DefaultHeader';
+
+const Solution: React.FC = () => {
+ const { isConnected } = useAccount();
+
+ return (
+
+
+
+
+ {isConnected ? : }
+
+
+
+ );
+};
+
+export default Solution;
diff --git a/packages/apps/fortune/exchange-oracle/client/src/providers/QueryClientProvider.tsx b/packages/apps/fortune/exchange-oracle/client/src/providers/QueryClientProvider.tsx
new file mode 100644
index 0000000000..2619587d98
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/providers/QueryClientProvider.tsx
@@ -0,0 +1,30 @@
+import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
+import { QueryClient } from '@tanstack/react-query';
+import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
+import { FC, PropsWithChildren } from 'react';
+import { deserialize, serialize } from 'wagmi';
+
+const queryClient = new QueryClient({
+ defaultOptions: {
+ queries: {
+ gcTime: 1_000 * 60 * 60 * 24, // 24 hours
+ },
+ },
+});
+
+const persister = createSyncStoragePersister({
+ serialize,
+ storage: window.localStorage,
+ deserialize,
+});
+
+export const QueryClientProvider: FC = ({ children }) => {
+ return (
+
+ {children}
+
+ );
+};
diff --git a/packages/apps/fortune/exchange-oracle/client/src/providers/SnackProvider.tsx b/packages/apps/fortune/exchange-oracle/client/src/providers/SnackProvider.tsx
new file mode 100644
index 0000000000..92c4823ee3
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/providers/SnackProvider.tsx
@@ -0,0 +1,50 @@
+import { Alert, Snackbar } from '@mui/material';
+import React, { createContext, useContext, useState } from 'react';
+import { parseErrorMessage } from '../utils/string';
+
+export const SnackbarContext = createContext({});
+
+const SnackbarProvider = ({ children }: { children: React.ReactElement }) => {
+ const [snackbarOpen, setSnackbarOpen] = useState(false);
+ const [snackbarMessage, setSnackbarMessage] = useState('');
+ const [snackbarSeverity, setSnackbarSeverity] = useState<
+ 'success' | 'error' | 'warning' | 'info'
+ >('success');
+
+ const openSnackbar = (
+ message: string,
+ severity: 'success' | 'error' | 'warning' | 'info'
+ ) => {
+ setSnackbarMessage(message);
+ setSnackbarSeverity(severity);
+ setSnackbarOpen(true);
+ };
+
+ const showError = (error: any) => {
+ openSnackbar(parseErrorMessage(error), 'error');
+ };
+
+ const handleCloseSnackbar = () => {
+ setSnackbarOpen(false);
+ };
+
+ return (
+
+ {children}
+
+
+ {snackbarMessage}
+
+
+
+ );
+};
+
+export const useSnackbar = () => useContext(SnackbarContext);
+
+export default SnackbarProvider;
diff --git a/packages/apps/fortune/exchange-oracle/client/src/providers/WagmiProvider.tsx b/packages/apps/fortune/exchange-oracle/client/src/providers/WagmiProvider.tsx
new file mode 100644
index 0000000000..2af879ee0b
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/providers/WagmiProvider.tsx
@@ -0,0 +1,56 @@
+import { ChainId } from '@human-protocol/sdk';
+
+import { FC, PropsWithChildren } from 'react';
+import { http, createConfig, WagmiProvider as WWagmiProvider } from 'wagmi';
+import * as wagmiChains from 'wagmi/chains';
+import { coinbaseWallet, walletConnect } from 'wagmi/connectors';
+
+import { RPC_URLS, LOCALHOST } from '../constants/chains';
+
+const projectId = import.meta.env.VITE_APP_WALLETCONNECT_PROJECT_ID;
+
+export const wagmiConfig = createConfig({
+ chains: [
+ wagmiChains.mainnet,
+ wagmiChains.sepolia,
+ wagmiChains.bsc,
+ wagmiChains.bscTestnet,
+ wagmiChains.polygon,
+ wagmiChains.polygonAmoy,
+ wagmiChains.moonbeam,
+ wagmiChains.moonbaseAlpha,
+ wagmiChains.avalancheFuji,
+ wagmiChains.avalanche,
+ wagmiChains.xLayer,
+ wagmiChains.xLayerTestnet,
+ LOCALHOST,
+ ],
+ connectors: [
+ walletConnect({
+ showQrModal: true,
+ projectId: projectId ?? '',
+ }),
+ coinbaseWallet({
+ appName: 'human-job-launcher',
+ }),
+ ],
+ transports: {
+ [wagmiChains.mainnet.id]: http(RPC_URLS[ChainId.MAINNET]),
+ [wagmiChains.sepolia.id]: http(RPC_URLS[ChainId.SEPOLIA]),
+ [wagmiChains.bsc.id]: http(RPC_URLS[ChainId.BSC_MAINNET]),
+ [wagmiChains.bscTestnet.id]: http(RPC_URLS[ChainId.BSC_TESTNET]),
+ [wagmiChains.polygon.id]: http(RPC_URLS[ChainId.POLYGON]),
+ [wagmiChains.polygonAmoy.id]: http(RPC_URLS[ChainId.POLYGON_AMOY]),
+ [wagmiChains.moonbeam.id]: http(RPC_URLS[ChainId.MOONBEAM]),
+ [wagmiChains.moonbaseAlpha.id]: http(RPC_URLS[ChainId.MOONBASE_ALPHA]),
+ [wagmiChains.avalanche.id]: http(RPC_URLS[ChainId.AVALANCHE]),
+ [wagmiChains.avalancheFuji.id]: http(RPC_URLS[ChainId.AVALANCHE_TESTNET]),
+ [wagmiChains.xLayer.id]: http(RPC_URLS[ChainId.XLAYER]),
+ [wagmiChains.xLayerTestnet.id]: http(RPC_URLS[ChainId.XLAYER_TESTNET]),
+ [LOCALHOST.id]: http(RPC_URLS[ChainId.LOCALHOST]),
+ },
+});
+
+export const WagmiProvider: FC = ({ children }) => {
+ return {children} ;
+};
diff --git a/packages/apps/fortune/exchange-oracle/client/src/services/job.ts b/packages/apps/fortune/exchange-oracle/client/src/services/job.ts
new file mode 100644
index 0000000000..7861141972
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/services/job.ts
@@ -0,0 +1,18 @@
+import { WalletClient } from 'viem';
+
+import { HUMAN_SIGNATURE_KEY } from '../constants';
+import api from '../utils/api';
+
+export const solveJob = async (signer: WalletClient, body: any) => {
+ if (!signer.account) {
+ throw new Error('Account not found');
+ }
+
+ const signature = await signer.signMessage({
+ account: signer.account,
+ message: JSON.stringify(body),
+ });
+ await api.post('/job/solve', body, {
+ headers: { [HUMAN_SIGNATURE_KEY]: signature },
+ });
+};
diff --git a/packages/apps/fortune/exchange-oracle/client/src/theme.ts b/packages/apps/fortune/exchange-oracle/client/src/theme.ts
new file mode 100644
index 0000000000..ae150fcc8e
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/theme.ts
@@ -0,0 +1,159 @@
+import { createTheme } from '@mui/material/styles';
+
+const theme = createTheme({
+ palette: {
+ primary: {
+ main: '#320a8d',
+ light: '#320a8d',
+ dark: '#4a148c',
+ },
+ info: {
+ main: '#eeeeee',
+ light: '#f5f5f5',
+ dark: '#bdbdbd',
+ },
+ secondary: {
+ main: '#858ec6',
+ light: '#6309ff',
+ dark: '#00867d',
+ contrastText: '#000',
+ },
+ text: {
+ primary: '#320a8d',
+ secondary: '#858ec6',
+ },
+ success: {
+ main: '#0E976E',
+ },
+ warning: {
+ main: '#FF9800',
+ },
+ error: {
+ main: '#F20D5F',
+ },
+ },
+ typography: {
+ fontFamily: 'Inter',
+ h2: {
+ fontSize: '80px',
+ lineHeight: 1.5,
+ letterSpacing: '-0.5px',
+ fontWeight: 800,
+ },
+ h4: {
+ fontSize: '34px',
+ fontWeight: 600,
+ },
+ h6: {
+ fontSize: '20px',
+ lineHeight: '160%',
+ },
+ body1: {
+ fontSize: '16px',
+ lineHeight: '28px',
+ },
+ body2: {
+ fontSize: '14px',
+ lineHeight: '24px',
+ },
+ },
+ components: {
+ MuiAlert: {
+ styleOverrides: {
+ outlinedSuccess: {
+ color: '#320a8d',
+ borderColor: '#320a8d',
+ },
+ // icon: {
+ // color: '#320a8d !important',
+ // },
+ },
+ },
+ MuiButton: {
+ styleOverrides: {
+ root: {
+ textTransform: 'none',
+ },
+ sizeLarge: {
+ fontSize: '15px',
+ fontWeight: '600',
+ lineHeight: '24px',
+ padding: '12px 24px',
+ },
+ },
+ },
+ MuiCard: {
+ styleOverrides: {
+ root: {
+ borderRadius: '16px',
+ background: '#fff',
+ boxShadow:
+ '0px 1px 5px 0px rgba(233, 235, 250, 0.20), 0px 2px 2px 0px rgba(233, 235, 250, 0.50), 0px 3px 1px -2px #E9EBFA',
+ },
+ },
+ },
+ MuiCardContent: {
+ styleOverrides: {
+ root: {
+ padding: '32px 20px 18px !important',
+ },
+ },
+ },
+ MuiLink: {
+ styleOverrides: {
+ root: {
+ textDecoration: 'none',
+ },
+ },
+ },
+ MuiOutlinedInput: {
+ styleOverrides: {
+ root: {
+ '&.Mui-focused .MuiOutlinedInput-notchedOutline': {
+ borderWidth: '1px',
+ },
+ },
+ notchedOutline: {
+ borderColor: '#858ec6',
+ },
+ },
+ },
+ MuiSelect: {
+ styleOverrides: {
+ icon: {
+ color: '#320a8d',
+ },
+ },
+ },
+ MuiToggleButton: {
+ styleOverrides: {
+ root: {
+ textTransform: 'none',
+ borderRadius: '8px',
+ border: '1px solid #320a8d',
+ color: '#320a8d',
+ fontWeight: 600,
+ fontSize: '14px',
+ '&.Mui-selected': {
+ background: '#320a8d',
+ color: '#fff',
+ },
+ '&.Mui-selected:hover': {
+ background: '#320a8d',
+ },
+ },
+ },
+ },
+ MuiMenuItem: {
+ styleOverrides: {
+ root: {
+ '&.Mui-selected': {
+ backgroundColor: '#f9faff',
+ },
+ },
+ },
+ },
+ },
+});
+
+export default theme;
diff --git a/packages/apps/fortune/exchange-oracle/client/src/utils/api.ts b/packages/apps/fortune/exchange-oracle/client/src/utils/api.ts
new file mode 100644
index 0000000000..bca4eacda4
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/utils/api.ts
@@ -0,0 +1,35 @@
+import axios from 'axios';
+import { CaseConverter } from './case-converter';
+
+const axiosInstance = axios.create({
+ baseURL: import.meta.env.VITE_APP_EXCHANGE_ORACLE_SERVER_URL,
+});
+
+axiosInstance.interceptors.request.use(
+ (config) => {
+ if (config.data) {
+ config.data = CaseConverter.transformToSnakeCase(config.data);
+ }
+
+ if (config.params) {
+ config.params = CaseConverter.transformToSnakeCase(config.params);
+ }
+
+ return config;
+ },
+ (error) => Promise.reject(error)
+);
+
+axiosInstance.interceptors.response.use(
+ (response) => {
+ if (response.data) {
+ response.data = CaseConverter.transformToCamelCase(response.data);
+ }
+ return response;
+ },
+ (error) => {
+ return Promise.reject(error);
+ }
+);
+
+export default axiosInstance;
diff --git a/packages/apps/fortune/exchange-oracle/client/src/utils/case-converter.ts b/packages/apps/fortune/exchange-oracle/client/src/utils/case-converter.ts
new file mode 100644
index 0000000000..37a195c1e8
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/utils/case-converter.ts
@@ -0,0 +1,37 @@
+export class CaseConverter {
+ static transformToCamelCase(obj: any): any {
+ if (Array.isArray(obj)) {
+ return obj.map((item) => CaseConverter.transformToCamelCase(item));
+ } else if (typeof obj === 'object' && obj !== null) {
+ return Object.keys(obj).reduce(
+ (acc: Record, key: string) => {
+ const camelCaseKey = key.replace(/_([a-z])/g, (g) =>
+ g[1].toUpperCase()
+ );
+ acc[camelCaseKey] = CaseConverter.transformToCamelCase(obj[key]);
+ return acc;
+ },
+ {}
+ );
+ } else {
+ return obj;
+ }
+ }
+
+ static transformToSnakeCase(obj: any): any {
+ if (Array.isArray(obj)) {
+ return obj.map((item) => CaseConverter.transformToSnakeCase(item));
+ } else if (typeof obj === 'object' && obj !== null) {
+ return Object.keys(obj).reduce(
+ (acc: Record, key: string) => {
+ const snakeCaseKey = key.replace(/([A-Z])/g, '_$1').toLowerCase();
+ acc[snakeCaseKey] = CaseConverter.transformToSnakeCase(obj[key]);
+ return acc;
+ },
+ {}
+ );
+ } else {
+ return obj;
+ }
+ }
+}
diff --git a/packages/apps/fortune/exchange-oracle/client/src/utils/string.ts b/packages/apps/fortune/exchange-oracle/client/src/utils/string.ts
new file mode 100644
index 0000000000..7607ad8d12
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/utils/string.ts
@@ -0,0 +1,10 @@
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export const parseErrorMessage = (error: any) => {
+ if (typeof error === 'string') {
+ return error;
+ }
+ if (error.response) {
+ return error.response?.data?.message ?? 'Something went wrong.';
+ }
+ return error.message ?? 'Something went wrong.';
+};
diff --git a/packages/apps/fortune/exchange-oracle/client/src/vite-env.d.ts b/packages/apps/fortune/exchange-oracle/client/src/vite-env.d.ts
new file mode 100644
index 0000000000..11f02fe2a0
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/src/vite-env.d.ts
@@ -0,0 +1 @@
+///
diff --git a/packages/apps/fortune/exchange-oracle/client/tsconfig.json b/packages/apps/fortune/exchange-oracle/client/tsconfig.json
new file mode 100644
index 0000000000..f9b958ceb0
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/tsconfig.json
@@ -0,0 +1,24 @@
+{
+ "extends": "../../../../../tsconfig.json",
+ "compilerOptions": {
+ "target": "es6",
+ "lib": ["dom", "dom.iterable", "esnext", "es2015.promise"],
+ "allowJs": true,
+ "skipLibCheck": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "strict": true,
+ "forceConsistentCasingInFileNames": true,
+ "noFallthroughCasesInSwitch": true,
+ "module": "esnext",
+ "moduleResolution": "node",
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+ "resolveJsonModule": true,
+ "downlevelIteration": true,
+ "baseUrl": ".",
+ "types": ["node", "jest", "@testing-library/jest-dom"]
+ },
+ "include": ["src", "tests"]
+}
diff --git a/packages/apps/fortune/exchange-oracle/client/vite.config.ts b/packages/apps/fortune/exchange-oracle/client/vite.config.ts
new file mode 100644
index 0000000000..10e0db7157
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/client/vite.config.ts
@@ -0,0 +1,31 @@
+///
+///
+
+import path from 'path';
+import react from '@vitejs/plugin-react';
+import { defineConfig } from 'vite';
+import { nodePolyfills } from 'vite-plugin-node-polyfills';
+
+// https://vitejs.dev/config/
+export default defineConfig({
+ plugins: [
+ react({ fastRefresh: false }),
+ nodePolyfills({
+ protocolImports: true,
+ }),
+ ],
+ resolve: {
+ alias: [{ find: 'src', replacement: path.resolve(__dirname, 'src') }],
+ },
+ optimizeDeps: {
+ include: ['@human-protocol/sdk'],
+ },
+ build: {
+ commonjsOptions: {
+ include: [/core/, /human-protocol-sdk/, /node_modules/],
+ },
+ },
+ server: {
+ port: 3006,
+ },
+});
diff --git a/packages/apps/fortune/exchange-oracle/server/.env.example b/packages/apps/fortune/exchange-oracle/server/.env.example
index 7f098db95e..4e8005d39f 100644
--- a/packages/apps/fortune/exchange-oracle/server/.env.example
+++ b/packages/apps/fortune/exchange-oracle/server/.env.example
@@ -20,6 +20,7 @@ S3_PORT=
S3_ACCESS_KEY=
S3_SECRET_KEY=
S3_USE_SSL=
+S3_BUCKET=
# Web3
WEB3_ENV=localhost
diff --git a/packages/apps/fortune/exchange-oracle/server/README.md b/packages/apps/fortune/exchange-oracle/server/README.md
index 9884f05c0c..92a7f6b570 100644
--- a/packages/apps/fortune/exchange-oracle/server/README.md
+++ b/packages/apps/fortune/exchange-oracle/server/README.md
@@ -1,25 +1,74 @@
-# Exchange Oracle Server
+
+
+
-Exchange Oracle Server is an API built with Nest in TypeScript that allows Human Protocol users to interact with created jobs. It provides endpoints to retrieve a list of jobs, get the job details
-and submit a solution using the worker address, escrow addres, chainId, and solution field.
+[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
+[circleci-url]: https://circleci.com/gh/nestjs/nest
-## Endpoints
+Fortune Exchange Oracle
+ Exchange Oracle is an API built with Nest in TypeScript that allows Human Protocol users to interact with created jobs. It provides endpoints to retrieve a list of jobs, get job details, view assignments, and submit solutions using worker address, escrow address, chainId, and solution field.
-### `GET /jobs`
+
+
+
+
+
-Returns a list of similar jobs in JSON format.
+
-### `POST /jobs/solutions`
+## ✨ Demo
-Receives job parameters in the request body and add a new to solution to the job based on address, chainId, and solution fields. Returns a JSON response with a boolean value indicating whether the job exists or not.
-
-## Installation
+First, let's install the dependencies, `yarn` is used as a package manager:
```bash
$ yarn install
```
-## Running the app
+The application needs access to environment variables in order to work correctly, for this, create one of the `.env.` files, depending on the state of your environment:
+
+```bash
+$ export NODE_ENV=development
+```
+
+Use the `.env.example` file as an example to create a configuration file with certain environment variables:
+
+```bash
+$ cp .env.example .env.development
+```
+
+Next, the requirement that the application puts forward is to set up a database, for this there are two different options, `manually` or using `docker`.
+
+### Set up the database manually
+
+First of all, postgres needs to be installed, please see here please see here .
+
+Then run the following commands in the postgres console to create the database and issue permissions:
+
+```bash
+$ CREATE DATABASE "exchange-oracle";
+$ CREATE USER operator WITH ENCRYPTED PASSWORD 'qwerty';
+$ GRANT ALL PRIVILEGES ON DATABASE "exchange-oracle" TO "operator";
+$ \c "exchange-oracle" postgres
+$ GRANT CREATE ON SCHEMA public TO operator;
+```
+
+Now we're ready to run the migrations:
+
+```bash
+yarn migration:run
+```
+
+### Set up the database with Docker
+
+To run with docker, you need to enter the following command, which raises the container with postgres and runs the migrations:
+
+```bash
+yarn docker:db:up
+```
+
+## 🚀 Usage
+
+### Running the app
```bash
# development
@@ -30,9 +79,12 @@ $ yarn run start:dev
# production mode
$ yarn run start:prod
+
+# debug mode
+$ yarn run start:debug
```
-## Test
+### Testing the app
```bash
# unit tests
@@ -45,10 +97,29 @@ $ yarn run test:e2e
$ yarn run test:cov
```
-## Contributing
+### Migrations
+
+```bash
+# Create new migration
+$ yarn migration:create addNameTable
+
+# Generate new migration
+$ yarn migration:generate addNameTable
+
+# Revert latest migration
+$ yarn migration:revert
+
+# Run all pending migrations
+$ yarn migration:run
+
+# Show all migrations
+$ yarn migration:show
+```
+
+## 📚 Documentation
-Contributions are welcome! Please create a pull request or open an issue for any improvements or bug fixes.
+For detailed information about the Exchange Oracle, please refer to the [Human Protocol Tech Docs](https://human-protocol.gitbook.io/hub/human-tech-docs/architecture/components/exchange-oracle).
-## License
+## 📝 License
-This project is licensed under the [MIT License](LICENSE).
+This project is licensed under the MIT License. See the [LICENSE](https://github.com/humanprotocol/human-protocol/blob/main/LICENSE) file for details.
diff --git a/packages/apps/fortune/exchange-oracle/server/package.json b/packages/apps/fortune/exchange-oracle/server/package.json
index d0606d1aec..6772002d99 100644
--- a/packages/apps/fortune/exchange-oracle/server/package.json
+++ b/packages/apps/fortune/exchange-oracle/server/package.json
@@ -28,18 +28,17 @@
},
"dependencies": {
"@human-protocol/sdk": "*",
- "@nestjs/axios": "^2.0.0",
+ "@nestjs/axios": "^3.0.2",
"@nestjs/common": "^10.2.7",
- "@nestjs/core": "^10.2.8",
- "@nestjs/platform-express": "^10.3.8",
- "joi": "^17.12.2",
- "reflect-metadata": "^0.1.13",
+ "@nestjs/core": "^10.3.10",
+ "joi": "^17.13.3",
+ "reflect-metadata": "^0.2.2",
"rxjs": "^7.2.0"
},
"devDependencies": {
- "@golevelup/ts-jest": "^0.4.0",
+ "@golevelup/ts-jest": "^0.5.0",
"@nestjs/cli": "^10.3.2",
- "@nestjs/schematics": "^9.2.0",
+ "@nestjs/schematics": "^10.1.3",
"@nestjs/testing": "^10.3.1",
"@types/express": "^4.17.13",
"@types/jest": "29.5.12",
@@ -53,8 +52,8 @@
"jest": "29.7.0",
"prettier": "^3.2.5",
"source-map-support": "^0.5.20",
- "supertest": "^6.3.4",
- "ts-jest": "29.1.1",
+ "supertest": "^7.0.0",
+ "ts-jest": "29.2.2",
"ts-loader": "^9.2.3",
"ts-node": "^10.9.2",
"tsconfig-paths": "4.2.0",
diff --git a/packages/apps/fortune/exchange-oracle/server/src/app.module.ts b/packages/apps/fortune/exchange-oracle/server/src/app.module.ts
index dfd5f2e1a5..ad8ea1bf49 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/app.module.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/app.module.ts
@@ -3,11 +3,10 @@ import { AppController } from './app.controller';
import { JobModule } from './modules/job/job.module';
import { ConfigModule } from '@nestjs/config';
import { envValidator } from './common/config';
-import { APP_GUARD, APP_INTERCEPTOR } from '@nestjs/core';
+import { APP_INTERCEPTOR } from '@nestjs/core';
import { SnakeCaseInterceptor } from './common/interceptors/snake-case';
import { DatabaseModule } from './database/database.module';
import { WebhookModule } from './modules/webhook/webhook.module';
-import { JwtAuthGuard } from './common/guards/jwt.auth';
import { JwtHttpStrategy } from './common/guards/strategy';
import { Web3Module } from './modules/web3/web3.module';
import { StatsModule } from './modules/stats/stats.module';
@@ -19,10 +18,6 @@ import { ScheduleModule } from '@nestjs/schedule';
@Module({
providers: [
- {
- provide: APP_GUARD,
- useClass: JwtAuthGuard,
- },
{
provide: APP_INTERCEPTOR,
useClass: SnakeCaseInterceptor,
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/config/env-schema.ts b/packages/apps/fortune/exchange-oracle/server/src/common/config/env-schema.ts
index 3a553bfe28..0567bb2238 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/config/env-schema.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/config/env-schema.ts
@@ -5,8 +5,8 @@ export const envValidator = Joi.object({
NODE_ENV: Joi.string(),
HOST: Joi.string(),
PORT: Joi.string(),
+ FE_URL: Joi.string(),
MAX_RETRY_COUNT: Joi.number(),
- CRON_SECRET: Joi.string().required(),
// Database
POSTGRES_HOST: Joi.string(),
POSTGRES_USER: Joi.string(),
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/config/server-config.service.ts b/packages/apps/fortune/exchange-oracle/server/src/common/config/server-config.service.ts
index fe72a1be91..4726aa9ca9 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/config/server-config.service.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/config/server-config.service.ts
@@ -13,10 +13,10 @@ export class ServerConfigService {
get port(): number {
return +this.configService.get('PORT', 5001);
}
+ get feURL(): string {
+ return this.configService.get('FE_URL', 'http://localhost:3006');
+ }
get maxRetryCount(): number {
return +this.configService.get('MAX_RETRY_COUNT', 5);
}
- get cronSecret(): string {
- return this.configService.get('CRON_SECRET', '');
- }
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/constant/errors.ts b/packages/apps/fortune/exchange-oracle/server/src/common/constant/errors.ts
index cfd11399fb..e37f946a53 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/constant/errors.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/constant/errors.ts
@@ -28,7 +28,8 @@ export enum ErrorCronJob {
*/
export enum ErrorAssignment {
NotFound = 'Assignment not found',
- InvalidStatus = 'Invalid assigment status',
+ InvalidStatus = 'Invalid assignment status',
+ InvalidAssignment = 'Invalid assignment',
InvalidUser = 'Assignment does not belong to the user',
AlreadyExists = 'Assignment already exists',
FullyAssigned = 'Fully assigned job',
@@ -48,4 +49,14 @@ export enum ErrorJob {
JobCompleted = 'This job has already been completed',
ManifestDecryptionFailed = 'Unable to decrypt manifest',
ManifestNotFound = 'Unable to get manifest',
+ NotFound = 'Job not found',
+ AlreadyCompleted = 'Job already completed',
+ AlreadyCanceled = 'Job already canceled',
+}
+
+/**
+ * Represents error messages associated with signatures.
+ */
+export enum ErrorSignature {
+ MissingRoles = 'Missing signature roles configuration',
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/decorators/role.ts b/packages/apps/fortune/exchange-oracle/server/src/common/decorators/role.ts
new file mode 100644
index 0000000000..d1be6b7f2d
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/decorators/role.ts
@@ -0,0 +1,5 @@
+import { SetMetadata } from '@nestjs/common';
+import { AuthSignatureRole, Role } from '../enums/role';
+
+export const AllowedRoles = (roles: AuthSignatureRole[] | Role[]) =>
+ SetMetadata('roles', roles);
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/enums/job.ts b/packages/apps/fortune/exchange-oracle/server/src/common/enums/job.ts
index bdb7d0f526..ce6c6e6181 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/enums/job.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/enums/job.ts
@@ -9,6 +9,7 @@ export enum JobSortField {
JOB_TYPE = 'job_type',
REWARD_AMOUNT = 'reward_amount',
CREATED_AT = 'created_at',
+ UPDATED_AT = 'updated_at',
}
export enum JobFieldName {
@@ -16,6 +17,7 @@ export enum JobFieldName {
RewardAmount = 'reward_amount',
RewardToken = 'reward_token',
CreatedAt = 'created_at',
+ UpdatedAt = 'updated_at',
}
export enum AssignmentStatus {
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/enums/role.ts b/packages/apps/fortune/exchange-oracle/server/src/common/enums/role.ts
index 55850ba398..621702f297 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/enums/role.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/enums/role.ts
@@ -1,5 +1,11 @@
-export enum Role {
+export enum AuthSignatureRole {
JobLauncher = 'job_launcher',
Recording = 'recording',
Reputation = 'reputation',
+ Worker = 'worker',
+}
+
+export enum Role {
+ Worker = 'WORKER',
+ HumanApp = 'HUMAN_APP',
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/enums/webhook.ts b/packages/apps/fortune/exchange-oracle/server/src/common/enums/webhook.ts
index eb841196c4..dea9e2f08c 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/enums/webhook.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/enums/webhook.ts
@@ -1,5 +1,6 @@
export enum EventType {
ESCROW_CREATED = 'escrow_created',
+ ESCROW_COMPLETED = 'escrow_completed',
ESCROW_CANCELED = 'escrow_canceled',
TASK_CREATION_FAILED = 'task_creation_failed',
SUBMISSION_REJECTED = 'submission_rejected',
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/guards/cron.auth.ts b/packages/apps/fortune/exchange-oracle/server/src/common/guards/cron.auth.ts
deleted file mode 100644
index 3fae0231ff..0000000000
--- a/packages/apps/fortune/exchange-oracle/server/src/common/guards/cron.auth.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import {
- CanActivate,
- ExecutionContext,
- Injectable,
- UnauthorizedException,
-} from '@nestjs/common';
-
-import { ServerConfigService } from '../config/server-config.service';
-
-@Injectable()
-export class CronAuthGuard implements CanActivate {
- constructor(private serverConfigService: ServerConfigService) {}
-
- public async canActivate(context: ExecutionContext): Promise {
- const request = context.switchToHttp().getRequest();
- if (
- request.headers['authorization'] !==
- `Bearer ${this.serverConfigService.cronSecret}`
- ) {
- throw new UnauthorizedException('Unauthorized');
- }
- return true;
- }
-}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/guards/jwt.auth.ts b/packages/apps/fortune/exchange-oracle/server/src/common/guards/jwt.auth.ts
index ff242ad42f..626469672f 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/guards/jwt.auth.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/guards/jwt.auth.ts
@@ -6,6 +6,8 @@ import {
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
+import { Role } from '../enums/role';
+import { JwtUser } from '../types/jwt';
@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt-http') implements CanActivate {
@@ -25,12 +27,25 @@ export class JwtAuthGuard extends AuthGuard('jwt-http') implements CanActivate {
}
// Try to authenticate with JWT
- try {
- // see https://github.com/nestjs/passport/blob/master/lib/auth.guard.ts
- return (await super.canActivate(context)) as boolean;
- } catch (jwtError) {
- console.error('JWT auth failed:', jwtError);
- throw new UnauthorizedException(jwtError.message);
+ const canActivate = (await super.canActivate(context)) as boolean;
+ if (!canActivate) {
+ throw new UnauthorizedException('JWT authentication failed');
}
+
+ // Roles verification
+ let roles = this.reflector.get('roles', context.getHandler());
+ if (!roles) roles = [Role.Worker];
+
+ const request = context.switchToHttp().getRequest();
+ const user = request.user as JwtUser;
+ if (!user) {
+ throw new UnauthorizedException('User not found in request');
+ }
+
+ if (!roles.includes(user.role)) {
+ throw new UnauthorizedException('Invalid role');
+ }
+
+ return true;
}
-}
\ No newline at end of file
+}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.spec.ts
index 3228e86231..2526286b65 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.spec.ts
@@ -3,12 +3,12 @@ import { ExecutionContext, UnauthorizedException } from '@nestjs/common';
import { SignatureAuthGuard } from './signature.auth';
import { verifySignature } from '../utils/signature';
import { ChainId, EscrowUtils } from '@human-protocol/sdk';
-import { MOCK_ADDRESS } from '../../../test/constants';
-import { Role } from '../enums/role';
+import { AuthSignatureRole } from '../enums/role';
import { HEADER_SIGNATURE_KEY } from '../constant';
+import { AssignmentRepository } from '../../modules/assignment/assignment.repository';
+import { Reflector } from '@nestjs/core';
-jest.mock('../../common/utils/signature');
-
+jest.mock('../utils/signature');
jest.mock('@human-protocol/sdk', () => ({
...jest.requireActual('@human-protocol/sdk'),
EscrowUtils: {
@@ -21,18 +21,27 @@ jest.mock('@human-protocol/sdk', () => ({
describe('SignatureAuthGuard', () => {
let guard: SignatureAuthGuard;
+ let reflector: Reflector;
+ let assignmentRepository: jest.Mocked;
beforeEach(async () => {
+ assignmentRepository = {
+ findOneById: jest.fn(),
+ } as any;
+
const module: TestingModule = await Test.createTestingModule({
providers: [
+ SignatureAuthGuard,
+ Reflector,
{
- provide: SignatureAuthGuard,
- useValue: new SignatureAuthGuard([Role.JobLauncher, Role.Recording]),
+ provide: AssignmentRepository,
+ useValue: assignmentRepository,
},
],
}).compile();
guard = module.get(SignatureAuthGuard);
+ reflector = module.get(Reflector);
});
it('should be defined', () => {
@@ -45,47 +54,111 @@ describe('SignatureAuthGuard', () => {
beforeEach(() => {
mockRequest = {
- switchToHttp: jest.fn().mockReturnThis(),
- getRequest: jest.fn().mockReturnThis(),
headers: {},
body: {},
- originalUrl: '',
};
context = {
switchToHttp: jest.fn().mockReturnThis(),
getRequest: jest.fn(() => mockRequest),
+ getHandler: jest.fn().mockReturnValue(() => {}),
} as any as ExecutionContext;
});
- it('should return true if signature is verified', async () => {
+ it('should return true if signature is verified for JobLauncher role', async () => {
+ reflector.get = jest
+ .fn()
+ .mockReturnValue([AuthSignatureRole.JobLauncher]);
+
mockRequest.headers[HEADER_SIGNATURE_KEY] = 'validSignature';
mockRequest.body = {
- escrow_address: MOCK_ADDRESS,
+ escrow_address: '0x123',
chain_id: ChainId.LOCALHOST,
};
(verifySignature as jest.Mock).mockReturnValue(true);
- const result = await guard.canActivate(context as any);
+ const result = await guard.canActivate(context);
expect(result).toBeTruthy();
expect(EscrowUtils.getEscrow).toHaveBeenCalledWith(
ChainId.LOCALHOST,
- MOCK_ADDRESS,
+ '0x123',
);
});
- it('should throw unauthorized exception if signature is not verified', async () => {
+ it('should throw UnauthorizedException if signature is not verified', async () => {
+ reflector.get = jest
+ .fn()
+ .mockReturnValue([AuthSignatureRole.JobLauncher]);
+
+ mockRequest.headers[HEADER_SIGNATURE_KEY] = 'invalidSignature';
+ mockRequest.body = {
+ escrow_address: '0x123',
+ chain_id: ChainId.LOCALHOST,
+ };
(verifySignature as jest.Mock).mockReturnValue(false);
- await expect(guard.canActivate(context as any)).rejects.toThrow(
+ await expect(guard.canActivate(context)).rejects.toThrow(
UnauthorizedException,
);
});
- it('should throw unauthorized exception for unrecognized oracle type', async () => {
- mockRequest.originalUrl = '/some/random/path';
- await expect(guard.canActivate(context as any)).rejects.toThrow(
+ it('should handle Worker role and verify signature', async () => {
+ reflector.get = jest.fn().mockReturnValue([AuthSignatureRole.Worker]);
+
+ mockRequest.headers[HEADER_SIGNATURE_KEY] = 'validSignature';
+ mockRequest.body = {
+ assignment_id: '1',
+ };
+ (verifySignature as jest.Mock).mockReturnValue(true);
+ assignmentRepository.findOneById.mockResolvedValue({
+ workerAddress: '0xworkerAddress',
+ } as any);
+
+ const result = await guard.canActivate(context);
+ expect(result).toBeTruthy();
+ expect(assignmentRepository.findOneById).toHaveBeenCalledWith('1');
+ });
+
+ it('should throw UnauthorizedException if assignment is not found for Worker role', async () => {
+ reflector.get = jest.fn().mockReturnValue([AuthSignatureRole.Worker]);
+
+ mockRequest.headers[HEADER_SIGNATURE_KEY] = 'validSignature';
+ mockRequest.body = {
+ assignment_id: '1',
+ };
+ (verifySignature as jest.Mock).mockReturnValue(true);
+ assignmentRepository.findOneById.mockResolvedValue(null);
+
+ await expect(guard.canActivate(context)).rejects.toThrow(
UnauthorizedException,
);
});
+
+ it('should handle multiple roles and verify signature', async () => {
+ reflector.get = jest
+ .fn()
+ .mockReturnValue([
+ AuthSignatureRole.JobLauncher,
+ AuthSignatureRole.Worker,
+ ]);
+
+ mockRequest.headers[HEADER_SIGNATURE_KEY] = 'validSignature';
+ mockRequest.body = {
+ escrow_address: '0x123',
+ chain_id: ChainId.LOCALHOST,
+ assignment_id: '1',
+ };
+ (verifySignature as jest.Mock).mockReturnValue(true);
+ assignmentRepository.findOneById.mockResolvedValue({
+ workerAddress: '0xworkerAddress',
+ } as any);
+
+ const result = await guard.canActivate(context);
+ expect(result).toBeTruthy();
+ expect(EscrowUtils.getEscrow).toHaveBeenCalledWith(
+ ChainId.LOCALHOST,
+ '0x123',
+ );
+ expect(assignmentRepository.findOneById).toHaveBeenCalledWith('1');
+ });
});
});
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.ts b/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.ts
index d43041d611..320fe38e59 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/guards/signature.auth.ts
@@ -2,37 +2,64 @@ import {
CanActivate,
ExecutionContext,
Injectable,
+ NotImplementedException,
UnauthorizedException,
} from '@nestjs/common';
import { verifySignature } from '../utils/signature';
import { HEADER_SIGNATURE_KEY } from '../constant';
import { EscrowUtils } from '@human-protocol/sdk';
-import { Role } from '../enums/role';
+import { AuthSignatureRole } from '../enums/role';
+import { Reflector } from '@nestjs/core';
+import { AssignmentRepository } from '../../modules/assignment/assignment.repository';
+import { ErrorAssignment, ErrorSignature } from '../constant/errors';
@Injectable()
export class SignatureAuthGuard implements CanActivate {
- constructor(private role: Role[]) {}
+ constructor(
+ private reflector: Reflector,
+ private readonly assignmentRepository: AssignmentRepository,
+ ) {}
- public async canActivate(context: ExecutionContext): Promise {
+ async canActivate(context: ExecutionContext): Promise {
+ const roles = this.reflector.get(
+ 'roles',
+ context.getHandler(),
+ );
+ if (!roles) throw new NotImplementedException(ErrorSignature.MissingRoles);
const request = context.switchToHttp().getRequest();
-
const data = request.body;
const signature = request.headers[HEADER_SIGNATURE_KEY];
const oracleAdresses: string[] = [];
- try {
+
+ if (roles.includes(AuthSignatureRole.Worker)) {
+ const assignment = await this.assignmentRepository.findOneById(
+ data.assignment_id,
+ );
+ if (assignment) {
+ oracleAdresses.push(assignment.workerAddress);
+ } else {
+ throw new UnauthorizedException(ErrorAssignment.NotFound);
+ }
+ } else {
const escrowData = await EscrowUtils.getEscrow(
data.chain_id,
data.escrow_address,
);
- if (this.role.includes(Role.JobLauncher))
+
+ if (roles.includes(AuthSignatureRole.JobLauncher)) {
oracleAdresses.push(escrowData.launcher);
- if (this.role.includes(Role.Recording))
+ }
+
+ if (roles.includes(AuthSignatureRole.Recording)) {
oracleAdresses.push(escrowData.recordingOracle!);
- if (this.role.includes(Role.Reputation))
- oracleAdresses.push(escrowData.reputationOracle!);
+ }
+ if (roles.includes(AuthSignatureRole.Reputation)) {
+ oracleAdresses.push(escrowData.reputationOracle!);
+ }
+ }
+ try {
const isVerified = verifySignature(data, signature, oracleAdresses);
-
if (isVerified) {
return true;
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/guards/strategy/jwt.http.ts b/packages/apps/fortune/exchange-oracle/server/src/common/guards/strategy/jwt.http.ts
index 1b5b9f7cff..24e48a853f 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/guards/strategy/jwt.http.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/guards/strategy/jwt.http.ts
@@ -7,6 +7,7 @@ import * as jwt from 'jsonwebtoken';
import { Web3Service } from '../../../modules/web3/web3.service';
import { JwtUser } from '../../../common/types/jwt';
import { JWT_KVSTORE_KEY, KYC_APPROVED } from '../../../common/constant';
+import { Role } from '../../../common/enums/role';
@Injectable()
export class JwtHttpStrategy extends PassportStrategy(Strategy, 'jwt-http') {
@@ -45,23 +46,51 @@ export class JwtHttpStrategy extends PassportStrategy(Strategy, 'jwt-http') {
public async validate(
@Req() request: any,
payload: {
+ role: string;
email: string;
- address: string;
+ wallet_address: string;
kyc_status: string;
reputation_network: string;
},
): Promise {
- if (!payload.kyc_status || !payload.email || !payload.address) {
- throw new UnauthorizedException('Invalid token');
+ if (!payload.email) {
+ throw new UnauthorizedException('Invalid token: missing email');
}
- if (payload.kyc_status !== KYC_APPROVED) {
- throw new UnauthorizedException('Invalid KYC status');
+
+ if (!payload.role) {
+ throw new UnauthorizedException('Invalid token: missing role');
+ }
+
+ if (!Object.values(Role).includes(payload.role as Role)) {
+ throw new UnauthorizedException(
+ `Invalid token: unrecognized role "${payload.role}"`,
+ );
}
+
+ const role: Role = payload.role as Role;
+
+ if (role !== Role.HumanApp) {
+ if (!payload.kyc_status) {
+ throw new UnauthorizedException('Invalid token: missing KYC status');
+ }
+
+ if (!payload.wallet_address) {
+ throw new UnauthorizedException('Invalid token: missing address');
+ }
+
+ if (payload.kyc_status !== KYC_APPROVED) {
+ throw new UnauthorizedException(
+ `Invalid token: expected KYC status "${KYC_APPROVED}", but received "${payload.kyc_status}"`,
+ );
+ }
+ }
+
return {
- address: payload.address,
+ role: role,
+ address: payload.wallet_address,
email: payload.email,
kycStatus: payload.kyc_status,
reputationNetwork: payload.reputation_network,
};
}
-}
\ No newline at end of file
+}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/common/types/jwt.ts b/packages/apps/fortune/exchange-oracle/server/src/common/types/jwt.ts
index 9f834446d7..79db0b992e 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/common/types/jwt.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/common/types/jwt.ts
@@ -1,8 +1,11 @@
+import { Role } from '../enums/role';
+
export interface RequestWithUser extends Request {
user: JwtUser;
}
export interface JwtUser {
+ role: Role;
email: string;
address: string;
kycStatus: string;
diff --git a/packages/apps/fortune/exchange-oracle/server/src/database/database.module.ts b/packages/apps/fortune/exchange-oracle/server/src/database/database.module.ts
index 877b042720..f67c3dd43e 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/database/database.module.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/database/database.module.ts
@@ -32,7 +32,7 @@ import { ServerConfigService } from '../common/config/server-config.service';
typeOrmLoggerService.setOptions(
loggerOptions && loggerOptions[0] === 'all'
? 'all'
- : (loggerOptions as LoggerOptions) ?? false,
+ : ((loggerOptions as LoggerOptions) ?? false),
);
return {
name: 'default',
diff --git a/packages/apps/fortune/exchange-oracle/server/src/database/migrations/1720453476309-AddEscrowCompletedEventTypeToWebhookTable.ts b/packages/apps/fortune/exchange-oracle/server/src/database/migrations/1720453476309-AddEscrowCompletedEventTypeToWebhookTable.ts
new file mode 100644
index 0000000000..9886b01111
--- /dev/null
+++ b/packages/apps/fortune/exchange-oracle/server/src/database/migrations/1720453476309-AddEscrowCompletedEventTypeToWebhookTable.ts
@@ -0,0 +1,54 @@
+import { MigrationInterface, QueryRunner } from 'typeorm';
+
+export class AddEscrowCompletedEventTypeToWebhookTable1720453476309
+ implements MigrationInterface
+{
+ name = 'AddEscrowCompletedEventTypeToWebhookTable1720453476309';
+
+ public async up(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`
+ ALTER TYPE "hmt"."webhooks_event_type_enum"
+ RENAME TO "webhooks_event_type_enum_old"
+ `);
+ await queryRunner.query(`
+ CREATE TYPE "hmt"."webhooks_event_type_enum" AS ENUM(
+ 'escrow_created',
+ 'escrow_completed',
+ 'escrow_canceled',
+ 'task_creation_failed',
+ 'submission_rejected',
+ 'submission_in_review'
+ )
+ `);
+ await queryRunner.query(`
+ ALTER TABLE "hmt"."webhooks"
+ ALTER COLUMN "event_type" TYPE "hmt"."webhooks_event_type_enum" USING "event_type"::"text"::"hmt"."webhooks_event_type_enum"
+ `);
+ await queryRunner.query(`
+ DROP TYPE "hmt"."webhooks_event_type_enum_old"
+ `);
+ }
+
+ public async down(queryRunner: QueryRunner): Promise {
+ await queryRunner.query(`
+ CREATE TYPE "hmt"."webhooks_event_type_enum_old" AS ENUM(
+ 'escrow_created',
+ 'escrow_canceled',
+ 'task_creation_failed',
+ 'submission_rejected',
+ 'submission_in_review'
+ )
+ `);
+ await queryRunner.query(`
+ ALTER TABLE "hmt"."webhooks"
+ ALTER COLUMN "event_type" TYPE "hmt"."webhooks_event_type_enum_old" USING "event_type"::"text"::"hmt"."webhooks_event_type_enum_old"
+ `);
+ await queryRunner.query(`
+ DROP TYPE "hmt"."webhooks_event_type_enum"
+ `);
+ await queryRunner.query(`
+ ALTER TYPE "hmt"."webhooks_event_type_enum_old"
+ RENAME TO "webhooks_event_type_enum"
+ `);
+ }
+}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts
index f7fb5ec895..458b3e3b14 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.spec.ts
@@ -37,7 +37,7 @@ describe('assignmentController', () => {
assignmentService = moduleRef.get(AssignmentService);
});
- describe('processWebhook', () => {
+ describe('getAssignmentList', () => {
it('should call assignmentService.getAssignmentList', async () => {
const query: GetAssignmentsDto = {
chainId: 80001,
@@ -69,16 +69,19 @@ describe('assignmentController', () => {
query,
userAddress,
reputationNetwork,
- expect.any(String),
);
});
+ });
+ describe('createAssignment', () => {
it('should call assignmentService.createAssignment', async () => {
const body: CreateAssignmentDto = {
chainId: 80001,
escrowAddress: escrowAddress,
};
- jest.spyOn(assignmentService, 'createAssignment').mockResolvedValue();
+ jest
+ .spyOn(assignmentService, 'createAssignment')
+ .mockResolvedValue({ id: 1 } as any);
await assignmentController.createAssignment(
{
user: { address: userAddress },
@@ -95,7 +98,7 @@ describe('assignmentController', () => {
it('should call jobService.resignJob', async () => {
const assignmentId = 123;
const resignJobDto: ResignDto = {
- assignmentId,
+ assignmentId: assignmentId.toString(),
};
jest.spyOn(assignmentService, 'resign').mockResolvedValue();
@@ -106,7 +109,7 @@ describe('assignmentController', () => {
);
expect(assignmentService.resign).toHaveBeenCalledWith(
- resignJobDto.assignmentId,
+ assignmentId,
userAddress,
);
});
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.ts
index efef89e382..d6a0a0ae52 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.controller.ts
@@ -17,6 +17,7 @@ import {
import { JwtAuthGuard } from '../../common/guards/jwt.auth';
import { AssignmentService } from './assignment.service';
import {
+ AssignJobResponseDto,
AssignmentDto,
CreateAssignmentDto,
GetAssignmentsDto,
@@ -53,11 +54,22 @@ export class AssignmentController {
description: 'Unauthorized. Missing or invalid credentials.',
})
@Post()
- createAssignment(
+ async createAssignment(
@Request() req: RequestWithUser,
@Body() body: CreateAssignmentDto,
- ): Promise {
- return this.assignmentService.createAssignment(body, req.user);
+ ): Promise {
+ const assignment = await this.assignmentService.createAssignment(
+ body,
+ req.user,
+ );
+
+ const response: AssignJobResponseDto = {
+ assignmentId: assignment.id.toString(),
+ escrowAddress: body.escrowAddress,
+ chainId: body.chainId,
+ workerAddress: assignment.workerAddress,
+ };
+ return response;
}
@ApiOperation({
@@ -82,18 +94,10 @@ export class AssignmentController {
@Request() req: RequestWithUser,
@Query() query: GetAssignmentsDto,
): any {
- let protocol = 'http';
-
- if ((req as any).secure) {
- protocol = 'https';
- }
-
- const serverUrl = `${protocol}://${(req.headers as any).host}`;
return this.assignmentService.getAssignmentList(
query,
req.user.address,
req.user.reputationNetwork,
- serverUrl,
);
}
@@ -123,6 +127,9 @@ export class AssignmentController {
@Request() req: RequestWithUser,
@Body() body: ResignDto,
): Promise {
- return this.assignmentService.resign(body.assignmentId, req.user.address);
+ return this.assignmentService.resign(
+ Number(body.assignmentId),
+ req.user.address,
+ );
}
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.dto.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.dto.ts
index 5aeaa295b6..27ba85011f 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.dto.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.dto.ts
@@ -1,7 +1,13 @@
import { ChainId } from '@human-protocol/sdk';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
-import { IsEnum, IsNumber, IsOptional, IsString } from 'class-validator';
+import {
+ IsEnum,
+ IsNumber,
+ IsOptional,
+ IsString,
+ IsDate,
+} from 'class-validator';
import {
AssignmentSortField,
AssignmentStatus,
@@ -58,11 +64,23 @@ export class GetAssignmentsDto extends PageOptionsDto {
@IsOptional()
@IsString()
assignmentId?: string;
+
+ @ApiPropertyOptional({ name: 'created_after' })
+ @IsOptional()
+ @Type(() => Date)
+ @IsDate()
+ createdAfter?: Date;
+
+ @ApiPropertyOptional({ name: 'updated_after' })
+ @IsOptional()
+ @Type(() => Date)
+ @IsDate()
+ updatedAfter?: Date;
}
export class AssignmentDto {
@ApiProperty({ name: 'assignment_id' })
- assignmentId: number;
+ assignmentId: string;
@ApiProperty({ name: 'escrow_address' })
escrowAddress: string;
@@ -95,7 +113,7 @@ export class AssignmentDto {
expiresAt: string;
constructor(
- assignmentId: number,
+ assignmentId: string,
escrowAddress: string,
chainId: number,
jobType: string,
@@ -119,6 +137,20 @@ export class AssignmentDto {
export class ResignDto {
@ApiProperty({ name: 'assignment_id' })
- @IsNumber()
- public assignmentId: number;
+ @IsString()
+ public assignmentId: string;
+}
+
+export class AssignJobResponseDto {
+ @ApiProperty({ name: 'assignment_id' })
+ assignmentId: string;
+
+ @ApiProperty({ name: 'escrow_address' })
+ escrowAddress: string;
+
+ @ApiProperty({ name: 'chain_id' })
+ chainId: ChainId;
+
+ @ApiProperty({ name: 'worker_address' })
+ workerAddress: string;
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.interface.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.interface.ts
index a591b3dea6..19b6d6fa58 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.interface.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.interface.ts
@@ -16,6 +16,8 @@ export interface AssignmentFilterData {
workerAddress: string;
reputationNetwork: string;
jobType?: JobType;
+ createdAfter?: Date;
+ updatedAfter?: Date;
}
export interface ListResult {
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.repository.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.repository.ts
index d9823f4bbd..7016994484 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.repository.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.repository.ts
@@ -39,27 +39,14 @@ export class AssignmentRepository extends BaseRepository {
});
}
- public async findOneByIdAndWorker(
+ public async findOneById(
assignmentId: number,
- workerAddress: string,
): Promise {
return this.findOne({
where: {
id: assignmentId,
- workerAddress,
- },
- });
- }
-
- public async findOneByEscrowAndWorker(
- escrowAddress: string,
- workerAddress: string,
- ): Promise {
- return this.findOne({
- where: {
- job: { escrowAddress },
- workerAddress,
},
+ relations: ['job'],
});
}
@@ -178,6 +165,18 @@ export class AssignmentRepository extends BaseRepository {
});
}
+ if (data.createdAfter) {
+ queryBuilder.andWhere('assignment.createdAt >= :createdAfter', {
+ createdAfter: data.createdAfter,
+ });
+ }
+
+ if (data.updatedAfter) {
+ queryBuilder.andWhere('assignment.updatedAt >= :updatedAfter', {
+ updatedAfter: data.updatedAfter,
+ });
+ }
+
queryBuilder.andWhere('job.reputationNetwork = :reputationNetwork', {
reputationNetwork: data.reputationNetwork,
});
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts
index c51103f46f..3de76048f7 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.spec.ts
@@ -1,11 +1,7 @@
import { createMock } from '@golevelup/ts-jest';
import { ConfigService } from '@nestjs/config';
import { Test } from '@nestjs/testing';
-import {
- MOCK_ADDRESS,
- MOCK_EXCHANGE_ORACLE,
- MOCK_PRIVATE_KEY,
-} from '../../../test/constants';
+import { MOCK_ADDRESS, MOCK_PRIVATE_KEY } from '../../../test/constants';
import { TOKEN } from '../../common/constant';
import { AssignmentStatus, JobType } from '../../common/enums/job';
import { AssignmentRepository } from '../assignment/assignment.repository';
@@ -21,7 +17,7 @@ import { SortDirection } from '../../common/enums/collection';
import { AssignmentEntity } from './assignment.entity';
import { ErrorAssignment } from '../../common/constant/errors';
import { BadRequestException } from '@nestjs/common';
-import { find } from 'rxjs';
+import { ServerConfigService } from '../../common/config/server-config.service';
jest.mock('@human-protocol/core/typechain-types', () => ({
...jest.requireActual('@human-protocol/core/typechain-types'),
@@ -79,10 +75,11 @@ describe('AssignmentService', () => {
createUnique: jest.fn(),
findOneByJobIdAndWorker: jest.fn(),
countByJobId: jest.fn(),
- findOneByIdAndWorker: jest.fn(),
+ findOneById: jest.fn(),
updateOne: jest.fn(),
},
},
+ ServerConfigService,
],
}).compile();
@@ -290,12 +287,11 @@ describe('AssignmentService', () => {
},
workerAddress,
reputationNetwork,
- MOCK_EXCHANGE_ORACLE,
);
expect(result.totalResults).toEqual(1);
expect(result.results[0]).toEqual({
- assignmentId: 1,
+ assignmentId: '1',
chainId: 1,
escrowAddress: escrowAddress,
jobType: JobType.FORTUNE,
@@ -344,7 +340,6 @@ describe('AssignmentService', () => {
},
workerAddress,
reputationNetwork,
- MOCK_EXCHANGE_ORACLE,
);
expect(result.totalResults).toEqual(0);
@@ -370,7 +365,6 @@ describe('AssignmentService', () => {
},
workerAddress,
reputationNetwork,
- MOCK_EXCHANGE_ORACLE,
);
expect(assignmentRepository.fetchFiltered).toHaveBeenCalledWith({
@@ -400,7 +394,7 @@ describe('AssignmentService', () => {
} as AssignmentEntity;
jest
- .spyOn(assignmentRepository, 'findOneByIdAndWorker')
+ .spyOn(assignmentRepository, 'findOneById')
.mockResolvedValue(mockAssignment);
await expect(
@@ -416,9 +410,7 @@ describe('AssignmentService', () => {
const assignmentId = 1;
const workerAddress = MOCK_ADDRESS;
- jest
- .spyOn(assignmentRepository, 'findOneByIdAndWorker')
- .mockResolvedValue(null);
+ jest.spyOn(assignmentRepository, 'findOneById').mockResolvedValue(null);
await expect(
assignmentService.resign(assignmentId, workerAddress),
@@ -435,7 +427,7 @@ describe('AssignmentService', () => {
} as AssignmentEntity;
jest
- .spyOn(assignmentRepository, 'findOneByIdAndWorker')
+ .spyOn(assignmentRepository, 'findOneById')
.mockResolvedValue(mockAssignment);
await expect(
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.ts
index 4d49410e6a..4f50d225e4 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/assignment/assignment.service.ts
@@ -15,22 +15,24 @@ import { JobService } from '../job/job.service';
import { Escrow__factory } from '@human-protocol/core/typechain-types';
import { Web3Service } from '../web3/web3.service';
import { ErrorAssignment } from '../../common/constant/errors';
+import { ServerConfigService } from '../../common/config/server-config.service';
@Injectable()
export class AssignmentService {
- public readonly logger = new Logger(AssignmentService.name);
+ private readonly logger = new Logger(AssignmentService.name);
constructor(
- public readonly assignmentRepository: AssignmentRepository,
- public readonly jobRepository: JobRepository,
- public readonly jobService: JobService,
- public readonly web3Service: Web3Service,
+ private readonly assignmentRepository: AssignmentRepository,
+ private readonly jobRepository: JobRepository,
+ private readonly jobService: JobService,
+ private readonly web3Service: Web3Service,
+ private readonly serverConfigService: ServerConfigService,
) {}
public async createAssignment(
data: CreateAssignmentDto,
jwtUser: JwtUser,
- ): Promise {
+ ): Promise {
const jobEntity = await this.jobRepository.findOneByChainIdAndEscrowAddress(
data.chainId,
data.escrowAddress,
@@ -87,14 +89,13 @@ export class AssignmentService {
newAssignmentEntity.rewardAmount =
manifest.fundAmount / manifest.submissionsRequired;
newAssignmentEntity.expiresAt = expirationDate;
- await this.assignmentRepository.createUnique(newAssignmentEntity);
+ return this.assignmentRepository.createUnique(newAssignmentEntity);
}
public async getAssignmentList(
data: GetAssignmentsDto,
workerAddress: string,
reputationNetwork: string,
- requestUrl: string,
): Promise> {
if (data.jobType && data.jobType !== JobType.FORTUNE)
return new PageDto(data.page!, data.pageSize!, 0, []);
@@ -110,7 +111,7 @@ export class AssignmentService {
const assignments = await Promise.all(
entities.map(async (entity) => {
const assignment = new AssignmentDto(
- entity.id,
+ entity.id.toString(),
entity.job.escrowAddress,
entity.job.chainId,
JobType.FORTUNE,
@@ -122,7 +123,10 @@ export class AssignmentService {
);
if (entity.status === AssignmentStatus.ACTIVE)
- assignment.url = requestUrl;
+ assignment.url =
+ this.serverConfigService.feURL +
+ '/assignment/' +
+ entity.id.toString();
else assignment.updatedAt = entity.updatedAt.toISOString();
return assignment;
@@ -132,14 +136,15 @@ export class AssignmentService {
}
async resign(assignmentId: number, workerAddress: string): Promise {
- const assignment = await this.assignmentRepository.findOneByIdAndWorker(
- assignmentId,
- workerAddress,
- );
+ const assignment =
+ await this.assignmentRepository.findOneById(assignmentId);
if (!assignment) {
throw new BadRequestException(ErrorAssignment.NotFound);
}
+ if (assignment.workerAddress !== workerAddress) {
+ throw new BadRequestException(ErrorAssignment.InvalidAssignment);
+ }
if (assignment.status !== AssignmentStatus.ACTIVE) {
throw new BadRequestException(ErrorAssignment.InvalidStatus);
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.controller.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.controller.spec.ts
deleted file mode 100644
index 5c439bc324..0000000000
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.controller.spec.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { createMock } from '@golevelup/ts-jest';
-import { ConfigService } from '@nestjs/config';
-import { Test } from '@nestjs/testing';
-import { ServerConfigService } from '../../common/config/server-config.service';
-import { CronJobController } from './cron-job.controller';
-import { CronJobService } from './cron-job.service';
-
-jest.mock('../../common/utils/signature');
-
-describe('cronJobController', () => {
- let cronJobController: CronJobController;
- let cronJobService: CronJobService;
-
- beforeAll(async () => {
- const moduleRef = await Test.createTestingModule({
- imports: [],
- controllers: [CronJobController],
- providers: [
- { provide: CronJobService, useValue: createMock() },
- ConfigService,
- ServerConfigService,
- ],
- }).compile();
-
- cronJobController = moduleRef.get(CronJobController);
- cronJobService = moduleRef.get(CronJobService);
- });
-
- describe('processPendingWebhooks', () => {
- it('should call cronJobService.processPendingWebhooks', async () => {
- jest.spyOn(cronJobService, 'processPendingWebhooks').mockResolvedValue();
- const result = await cronJobController.processPendingWebhooks();
- expect(result).toBe(undefined);
- expect(cronJobService.processPendingWebhooks).toHaveBeenCalledWith();
- });
- });
-});
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.controller.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.controller.ts
deleted file mode 100644
index 6ffa2ce637..0000000000
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.controller.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Controller, Get, UseGuards } from '@nestjs/common';
-import {
- ApiBearerAuth,
- ApiOperation,
- ApiResponse,
- ApiTags,
-} from '@nestjs/swagger';
-import { CronJobService } from './cron-job.service';
-import { CronAuthGuard } from '../../common/guards/cron.auth';
-import { Public } from '../../common/decorators';
-
-@Public()
-@UseGuards(CronAuthGuard)
-@ApiTags('Cron')
-@Controller('/cron')
-export class CronJobController {
- constructor(private readonly cronJobService: CronJobService) {}
-
- @ApiOperation({
- summary: 'Process pending webhooks cron job',
- description: 'Endpoint to launch Process pending webhooks cron job.',
- })
- @ApiResponse({
- status: 200,
- description: 'Cron job launched successfully.',
- })
- @ApiResponse({
- status: 400,
- description: 'Bad Request. Invalid input parameters.',
- })
- @ApiBearerAuth()
- @Get('/webhook/process')
- public async processPendingWebhooks(): Promise {
- await this.cronJobService.processPendingWebhooks();
- return;
- }
-}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.module.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.module.ts
index c452566d00..67e2aaed34 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.module.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/cron-job/cron-job.module.ts
@@ -7,7 +7,6 @@ import { WebhookRepository } from '../webhook/webhook.repository';
import { CronJobEntity } from './cron-job.entity';
import { CronJobRepository } from './cron-job.repository';
import { CronJobService } from './cron-job.service';
-import { CronJobController } from './cron-job.controller';
@Global()
@Module({
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.spec.ts
index 4471098a40..b53f28a52d 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.spec.ts
@@ -1,9 +1,12 @@
import { createMock } from '@golevelup/ts-jest';
import { Test } from '@nestjs/testing';
-import { RequestWithUser } from 'src/common/types/jwt';
+import { RequestWithUser } from '../../common/types/jwt';
import { JobController } from './job.controller';
-import { SolveJobDto } from './job.dto';
+import { GetJobsDto, SolveJobDto, JobDto } from './job.dto';
import { JobService } from './job.service';
+import { JobSortField, JobStatus, JobType } from '../../common/enums/job';
+import { PageDto } from '../../common/pagination/pagination.dto';
+import { AssignmentRepository } from '../assignment/assignment.repository';
jest.mock('../../common/utils/signature');
@@ -11,15 +14,17 @@ describe('JobController', () => {
let jobController: JobController;
let jobService: JobService;
- const chainId = 1;
- const escrowAddress = '0x1234567890123456789012345678901234567890';
- const workerAddress = '0x1234567890123456789012345678901234567891';
-
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [],
controllers: [JobController],
- providers: [{ provide: JobService, useValue: createMock() }],
+ providers: [
+ { provide: JobService, useValue: createMock() },
+ {
+ provide: AssignmentRepository,
+ useValue: createMock(),
+ },
+ ],
}).compile();
jobController = moduleRef.get(JobController);
@@ -28,53 +33,52 @@ describe('JobController', () => {
describe('getJobs', () => {
it('should call jobService.getJobList', async () => {
- const solution = 'job-solution';
- const solveJobDto: SolveJobDto = {
- chainId,
- escrowAddress,
- solution,
+ const getJobsDto: GetJobsDto = {
+ sortField: JobSortField.CREATED_AT,
+ chainId: 1,
+ jobType: JobType.FORTUNE,
+ fields: [],
+ escrowAddress: '0x1234567890123456789012345678901234567890',
+ status: JobStatus.ACTIVE,
+ page: 1,
+ pageSize: 10,
+ skip: 0,
};
- jest.spyOn(jobService, 'solveJob').mockResolvedValue();
+ const req = {
+ user: { reputationNetwork: 'network' },
+ } as RequestWithUser;
- await jobController.solveJob(
- {
- user: { address: workerAddress },
- } as RequestWithUser,
- solveJobDto,
- );
+ const pageDto: PageDto = {
+ results: [],
+ totalResults: 0,
+ totalPages: 0,
+ pageSize: 10,
+ page: 1,
+ };
- expect(jobService.solveJob).toHaveBeenCalledWith(
- solveJobDto.chainId,
- solveJobDto.escrowAddress,
- workerAddress,
- solveJobDto.solution,
+ jest.spyOn(jobService, 'getJobList').mockResolvedValue(pageDto);
+
+ await jobController.getJobs(req, getJobsDto);
+
+ expect(jobService.getJobList).toHaveBeenCalledWith(
+ getJobsDto,
+ req.user.reputationNetwork,
);
});
});
describe('solveJob', () => {
it('should call jobService.solveJob', async () => {
- const solution = 'job-solution';
const solveJobDto: SolveJobDto = {
- chainId,
- escrowAddress,
- solution,
+ assignmentId: '1',
+ solution: 'job-solution',
};
- jest.spyOn(jobService, 'solveJob').mockResolvedValue();
-
- await jobController.solveJob(
- {
- user: { address: workerAddress },
- } as RequestWithUser,
- solveJobDto,
- );
+ await jobController.solveJob('signature', solveJobDto);
expect(jobService.solveJob).toHaveBeenCalledWith(
- solveJobDto.chainId,
- solveJobDto.escrowAddress,
- workerAddress,
+ Number(solveJobDto.assignmentId),
solveJobDto.solution,
);
});
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.ts
index 9cfbb9a828..cdf38402eb 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.controller.ts
@@ -6,31 +6,40 @@ import {
Query,
UseGuards,
Request,
+ Headers,
} from '@nestjs/common';
import {
ApiBearerAuth,
ApiTags,
ApiOperation,
+ ApiHeader,
ApiResponse,
ApiBody,
} from '@nestjs/swagger';
import { JwtAuthGuard } from '../../common/guards/jwt.auth';
-import { GetJobsDto, JobDto, SolveJobDto } from './job.dto';
+import {
+ GetJobsDto,
+ JobDto,
+ SolveJobDto,
+ SolveJobResponseDto,
+} from './job.dto';
import { JobService } from './job.service';
+import { HEADER_SIGNATURE_KEY } from '../../common/constant';
import { RequestWithUser } from '../../common/types/jwt';
import { PageDto } from '../../common/pagination/pagination.dto';
+import { AuthSignatureRole, Role } from '../../common/enums/role';
+import { SignatureAuthGuard } from '../../common/guards/signature.auth';
+import { AllowedRoles } from '../../common/decorators/role';
@ApiTags('Job')
@Controller('job')
-@UseGuards(JwtAuthGuard)
-@ApiBearerAuth()
export class JobController {
constructor(private readonly jobService: JobService) {}
+
@ApiOperation({
summary: 'Get Jobs',
description: 'Endpoint to retrieve a list of jobs.',
})
- @ApiBearerAuth()
@ApiResponse({
status: 200,
type: PageDto,
@@ -44,6 +53,9 @@ export class JobController {
status: 401,
description: 'Unauthorized. Missing or invalid credentials.',
})
+ @UseGuards(JwtAuthGuard)
+ @AllowedRoles([Role.Worker, Role.HumanApp])
+ @ApiBearerAuth()
@Get()
getJobs(
@Request() req: RequestWithUser,
@@ -56,7 +68,11 @@ export class JobController {
summary: 'Solve Job',
description: 'Endpoint to solve a job.',
})
- @ApiBearerAuth()
+ @ApiHeader({
+ name: HEADER_SIGNATURE_KEY,
+ description: 'Signature header for authenticating the webhook request.',
+ required: true,
+ })
@ApiBody({
description: 'Details required to solve the job.',
type: SolveJobDto,
@@ -64,6 +80,7 @@ export class JobController {
@ApiResponse({
status: 200,
description: 'Job solved successfully.',
+ type: SolveJobResponseDto,
})
@ApiResponse({
status: 400,
@@ -74,15 +91,21 @@ export class JobController {
description: 'Unauthorized. Missing or invalid credentials.',
})
@Post('solve')
- solveJob(
- @Request() req: RequestWithUser,
- @Body() body: SolveJobDto,
- ): Promise {
- return this.jobService.solveJob(
- body.chainId,
- body.escrowAddress,
- req.user.address,
- body.solution,
- );
+ @UseGuards(SignatureAuthGuard)
+ @AllowedRoles([AuthSignatureRole.Worker])
+ async solveJob(
+ @Headers(HEADER_SIGNATURE_KEY) signature: string,
+ @Body() solveJobDto: SolveJobDto,
+ ): Promise {
+ const { assignmentId, solution } = solveJobDto;
+
+ await this.jobService.solveJob(Number(assignmentId), solution);
+
+ const response: SolveJobResponseDto = {
+ assignmentId,
+ solution,
+ message: 'Job solved successfully.',
+ };
+ return response;
}
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.dto.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.dto.ts
index 445fc84ea7..37c9818dff 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.dto.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.dto.ts
@@ -1,8 +1,12 @@
-import { ChainId } from '@human-protocol/sdk';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
-import { IsOptional, IsEnum, IsString, IsNumber } from 'class-validator';
+import {
+ IsOptional,
+ IsEnum,
+ IsString,
+ IsNumber,
+ IsDate,
+} from 'class-validator';
import { Type } from 'class-transformer';
-import { IsValidEthereumAddress } from '../../common/validators';
import {
JobFieldName,
JobSortField,
@@ -19,21 +23,13 @@ export class ManifestDto {
}
export class SolveJobDto {
- @ApiProperty({ name: 'escrow_address' })
- @IsString()
- @IsValidEthereumAddress()
- public escrowAddress: string;
-
- @ApiProperty({
- enum: ChainId,
- name: 'chain_id',
- })
- @IsEnum(ChainId)
- public chainId: ChainId;
-
@ApiProperty()
@IsString()
public solution: string;
+
+ @ApiProperty({ name: 'assignment_id' })
+ @IsString()
+ public assignmentId: string;
}
export class GetJobsDto extends PageOptionsDto {
@@ -71,6 +67,18 @@ export class GetJobsDto extends PageOptionsDto {
@IsEnum(JobStatus)
@IsOptional()
status: JobStatus;
+
+ @ApiPropertyOptional({ name: 'created_after' })
+ @IsOptional()
+ @Type(() => Date)
+ @IsDate()
+ createdAfter?: Date;
+
+ @ApiPropertyOptional({ name: 'updated_after' })
+ @IsOptional()
+ @Type(() => Date)
+ @IsDate()
+ updatedAfter?: Date;
}
export class JobDto {
@@ -98,6 +106,9 @@ export class JobDto {
@ApiProperty({ name: 'created_at' })
createdAt?: string;
+ @ApiProperty({ name: 'updated_at' })
+ updatedAt?: string;
+
constructor(
escrowAddress: string,
chainId: number,
@@ -110,3 +121,14 @@ export class JobDto {
this.status = status;
}
}
+
+export class SolveJobResponseDto {
+ @ApiProperty({ name: 'assignment_id' })
+ assignmentId: string;
+
+ @ApiProperty({ name: 'solution' })
+ solution: string;
+
+ @ApiProperty({ name: 'message' })
+ message: string;
+}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.entity.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.entity.ts
index dd6cb14fd8..b5d710b0f4 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.entity.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.entity.ts
@@ -23,6 +23,8 @@ export class JobEntity extends BaseEntity {
@Column({ type: 'varchar' })
public reputationNetwork: string;
- @OneToMany(() => AssignmentEntity, (assignment) => assignment.job)
+ @OneToMany(() => AssignmentEntity, (assignment) => assignment.job, {
+ cascade: true,
+ })
public assignments: AssignmentEntity[];
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.interface.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.interface.ts
index b7fbea5382..264b1a2360 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.interface.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.interface.ts
@@ -11,6 +11,8 @@ export interface JobFilterData {
skip: number;
pageSize: number;
reputationNetwork: string;
+ createdAfter?: Date;
+ updatedAfter?: Date;
}
export interface ListResult {
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.module.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.module.ts
index 37201ef89a..a687b5a3d1 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.module.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.module.ts
@@ -15,9 +15,7 @@ import { AssignmentRepository } from '../assignment/assignment.repository';
@Module({
imports: [
- TypeOrmModule.forFeature([JobEntity]),
- TypeOrmModule.forFeature([WebhookEntity]),
- TypeOrmModule.forFeature([AssignmentEntity]),
+ TypeOrmModule.forFeature([JobEntity, WebhookEntity, AssignmentEntity]),
ConfigModule,
HttpModule,
Web3Module,
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.repository.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.repository.ts
index 90e7c8ffb5..2203d14a62 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.repository.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.repository.ts
@@ -4,7 +4,7 @@ import { ConfigService } from '@nestjs/config';
import { DataSource } from 'typeorm';
import { BaseRepository } from '../../database/base.repository';
import { JobEntity } from './job.entity';
-import { JobSortField } from '../../common/enums/job';
+import { JobSortField, JobStatus } from '../../common/enums/job';
import { JobFilterData, ListResult } from './job.interface';
@Injectable()
@@ -36,12 +36,26 @@ export class JobRepository extends BaseRepository {
});
}
+ public async findOneByChainIdAndEscrowAddressWithAssignments(
+ chainId: number,
+ escrowAddress: string,
+ ): Promise {
+ return this.findOne({
+ where: {
+ chainId,
+ escrowAddress,
+ },
+ relations: ['assignments'],
+ });
+ }
+
public async fetchFiltered(data: JobFilterData): Promise {
const queryBuilder = this.createQueryBuilder('job');
if (
data.sortField == JobSortField.CHAIN_ID ||
- data.sortField == JobSortField.CREATED_AT
+ data.sortField == JobSortField.CREATED_AT ||
+ data.sortField == JobSortField.UPDATED_AT
)
queryBuilder.orderBy(data.sortField!, data.sort);
@@ -59,6 +73,18 @@ export class JobRepository extends BaseRepository {
queryBuilder.andWhere('job.status = :status', { status: data.status });
}
+ if (data.createdAfter) {
+ queryBuilder.andWhere('job.createdAt >= :createdAfter', {
+ createdAfter: data.createdAfter,
+ });
+ }
+
+ if (data.updatedAfter) {
+ queryBuilder.andWhere('job.updatedAt >= :updatedAfter', {
+ updatedAfter: data.updatedAfter,
+ });
+ }
+
queryBuilder.andWhere('job.reputationNetwork = :reputationNetwork', {
reputationNetwork: data.reputationNetwork,
});
@@ -69,4 +95,12 @@ export class JobRepository extends BaseRepository {
const { entities } = await queryBuilder.getRawAndEntities();
return { entities, itemCount };
}
+
+ public async countJobsByStatus(status: JobStatus): Promise {
+ return this.count({
+ where: {
+ status,
+ },
+ });
+ }
}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.spec.ts
index b19b65d6d7..346c8bc684 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.spec.ts
@@ -29,6 +29,8 @@ import { JobRepository } from './job.repository';
import { JobService } from './job.service';
import { PGPConfigService } from '../../common/config/pgp-config.service';
import { S3ConfigService } from '../../common/config/s3-config.service';
+import { ErrorJob, ErrorAssignment } from '../../common/constant/errors';
+import { BadRequestException, NotFoundException } from '@nestjs/common';
jest.mock('@human-protocol/sdk', () => ({
...jest.requireActual('@human-protocol/sdk'),
@@ -170,6 +172,154 @@ describe('JobService', () => {
});
});
+ describe('completeJob', () => {
+ const chainId = 1;
+ const escrowAddress = '0x1234567890123456789012345678901234567890';
+
+ const webhook: WebhookDto = {
+ chainId,
+ escrowAddress,
+ eventType: EventType.ESCROW_COMPLETED,
+ };
+
+ it('should complete a job and update all related assignments', async () => {
+ const jobEntity = new JobEntity();
+ jobEntity.chainId = chainId;
+ jobEntity.escrowAddress = escrowAddress;
+ jobEntity.status = JobStatus.ACTIVE;
+ jobEntity.assignments = [
+ {
+ id: 1,
+ jobId: jobEntity.id,
+ status: AssignmentStatus.ACTIVE,
+ } as AssignmentEntity,
+ {
+ id: 2,
+ jobId: jobEntity.id,
+ status: AssignmentStatus.ACTIVE,
+ } as AssignmentEntity,
+ ];
+
+ jest
+ .spyOn(jobRepository, 'findOneByChainIdAndEscrowAddressWithAssignments')
+ .mockResolvedValue(jobEntity);
+
+ await jobService.completeJob(webhook);
+
+ expect(
+ jobRepository.findOneByChainIdAndEscrowAddressWithAssignments,
+ ).toHaveBeenCalledWith(chainId, escrowAddress);
+ expect(jobRepository.save).toHaveBeenCalledWith(
+ expect.objectContaining({
+ status: JobStatus.COMPLETED,
+ assignments: [
+ { id: 1, jobId: jobEntity.id, status: AssignmentStatus.COMPLETED },
+ { id: 2, jobId: jobEntity.id, status: AssignmentStatus.COMPLETED },
+ ],
+ }),
+ );
+ });
+
+ it('should throw NotFoundException if job does not exist', async () => {
+ jest
+ .spyOn(jobRepository, 'findOneByChainIdAndEscrowAddressWithAssignments')
+ .mockResolvedValue(null);
+
+ await expect(jobService.completeJob(webhook)).rejects.toThrow(
+ new NotFoundException(ErrorJob.NotFound),
+ );
+ });
+
+ it('should throw BadRequestException if job is already completed', async () => {
+ const jobEntity = new JobEntity();
+ jobEntity.chainId = chainId;
+ jobEntity.escrowAddress = escrowAddress;
+ jobEntity.status = JobStatus.COMPLETED;
+
+ jest
+ .spyOn(jobRepository, 'findOneByChainIdAndEscrowAddressWithAssignments')
+ .mockResolvedValue(jobEntity);
+
+ await expect(jobService.completeJob(webhook)).rejects.toThrow(
+ new BadRequestException(ErrorJob.AlreadyCompleted),
+ );
+ });
+ });
+
+ describe('cancelJob', () => {
+ const chainId = 1;
+ const escrowAddress = '0x1234567890123456789012345678901234567890';
+
+ const webhook: WebhookDto = {
+ chainId,
+ escrowAddress,
+ eventType: EventType.ESCROW_CANCELED,
+ };
+
+ it('should cancel a job and update all related assignments', async () => {
+ const jobEntity = new JobEntity();
+ jobEntity.chainId = chainId;
+ jobEntity.escrowAddress = escrowAddress;
+ jobEntity.status = JobStatus.ACTIVE;
+ jobEntity.assignments = [
+ {
+ id: 1,
+ jobId: jobEntity.id,
+ status: AssignmentStatus.ACTIVE,
+ } as AssignmentEntity,
+ {
+ id: 2,
+ jobId: jobEntity.id,
+ status: AssignmentStatus.ACTIVE,
+ } as AssignmentEntity,
+ ];
+
+ jest
+ .spyOn(jobRepository, 'findOneByChainIdAndEscrowAddressWithAssignments')
+ .mockResolvedValue(jobEntity);
+
+ await jobService.cancelJob(webhook);
+
+ expect(
+ jobRepository.findOneByChainIdAndEscrowAddressWithAssignments,
+ ).toHaveBeenCalledWith(chainId, escrowAddress);
+ expect(jobRepository.save).toHaveBeenCalledWith(
+ expect.objectContaining({
+ status: JobStatus.CANCELED,
+ assignments: [
+ { id: 1, jobId: jobEntity.id, status: AssignmentStatus.CANCELED },
+ { id: 2, jobId: jobEntity.id, status: AssignmentStatus.CANCELED },
+ ],
+ }),
+ );
+ });
+
+ it('should throw NotFoundException if job does not exist', async () => {
+ jest
+ .spyOn(jobRepository, 'findOneByChainIdAndEscrowAddressWithAssignments')
+ .mockResolvedValue(null);
+
+ await expect(jobService.cancelJob(webhook)).rejects.toThrow(
+ new NotFoundException(ErrorJob.NotFound),
+ );
+ });
+
+ it('should throw BadRequestException if job is already canceled', async () => {
+ const jobEntity = new JobEntity();
+ jobEntity.chainId = chainId;
+ jobEntity.escrowAddress = escrowAddress;
+ jobEntity.status = JobStatus.CANCELED;
+
+ jest
+ .spyOn(jobRepository, 'findOneByChainIdAndEscrowAddressWithAssignments')
+ .mockResolvedValue(jobEntity);
+
+ await expect(jobService.cancelJob(webhook)).rejects.toThrow(
+ new BadRequestException(ErrorJob.AlreadyCanceled),
+ );
+ });
+ });
+
describe('getJobList', () => {
const jobs = [
{
@@ -260,10 +410,15 @@ describe('JobService', () => {
describe('solveJob', () => {
const assignment = {
+ id: 1,
jobId: 1,
workerAddress: workerAddress,
status: AssignmentStatus.ACTIVE,
- };
+ job: {
+ escrowAddress,
+ chainId,
+ },
+ } as AssignmentEntity;
beforeAll(async () => {
(EscrowClient.build as any).mockImplementation(() => ({
@@ -286,7 +441,7 @@ describe('JobService', () => {
};
jest
- .spyOn(assignmentRepository, 'findOneByEscrowAndWorker')
+ .spyOn(assignmentRepository, 'findOneById')
.mockResolvedValue(assignment as AssignmentEntity);
storageService.downloadJobSolutions = jest.fn().mockResolvedValueOnce([]);
@@ -307,12 +462,7 @@ describe('JobService', () => {
.fn()
.mockResolvedValue(solutionsUrl);
- await jobService.solveJob(
- chainId,
- escrowAddress,
- workerAddress,
- 'solution',
- );
+ await jobService.solveJob(assignment.id, 'solution');
expect(web3Service.getSigner).toHaveBeenCalledWith(chainId);
expect(webhookRepository.createUnique).toHaveBeenCalledWith({
escrowAddress,
@@ -325,13 +475,21 @@ describe('JobService', () => {
expect(assignment.status).toBe(AssignmentStatus.VALIDATION);
});
+ it('should fail if assignment status is not ACTIVE', async () => {
+ assignment.status = AssignmentStatus.CANCELED;
+
+ await expect(jobService.solveJob(1, 'solution')).rejects.toThrow(
+ new BadRequestException(ErrorAssignment.InvalidStatus),
+ );
+ expect(web3Service.getSigner).toHaveBeenCalledWith(chainId);
+ });
+
it('should fail if user is not assigned to the job', async () => {
- jest
- .spyOn(assignmentRepository, 'findOneByEscrowAndWorker')
- .mockResolvedValue(null);
- await expect(
- jobService.solveJob(chainId, escrowAddress, workerAddress, 'solution'),
- ).rejects.toThrow('User is not assigned to the job');
+ jest.spyOn(assignmentRepository, 'findOneById').mockResolvedValue(null);
+
+ await expect(jobService.solveJob(1, 'solution')).rejects.toThrow(
+ 'Assignment not found',
+ );
});
it('should fail if job has already been completed', async () => {
@@ -342,13 +500,14 @@ describe('JobService', () => {
fundAmount: 100,
};
+ assignment.status = AssignmentStatus.ACTIVE;
+
jest
- .spyOn(assignmentRepository, 'findOneByEscrowAndWorker')
+ .spyOn(assignmentRepository, 'findOneById')
.mockResolvedValue(assignment as AssignmentEntity);
storageService.downloadJobSolutions = jest.fn().mockResolvedValueOnce([
{
- exchangeAddress: '0x1234567890123456789012345678901234567892',
workerAddress: '0x1234567890123456789012345678901234567892',
solution: 'test',
},
@@ -362,55 +521,44 @@ describe('JobService', () => {
decrypt: jest.fn().mockResolvedValue(JSON.stringify(manifest)),
}));
- const recordingOracleURLMock = 'https://example.com/recordingoracle';
-
- OperatorUtils.getLeader = jest.fn().mockResolvedValue({
- webhookUrl: recordingOracleURLMock,
- });
-
- await expect(
- jobService.solveJob(chainId, escrowAddress, workerAddress, 'solution'),
- ).rejects.toThrow('This job has already been completed');
- expect(web3Service.getSigner).toHaveBeenCalledWith(chainId);
- });
-
- it('should fail if the escrow address is invalid', async () => {
- const escrowAddress = 'invalid_address';
- const solution = 'job-solution';
-
- await expect(
- jobService.solveJob(chainId, escrowAddress, workerAddress, solution),
- ).rejects.toThrow('Invalid address');
+ await expect(jobService.solveJob(1, 'solution')).rejects.toThrow(
+ 'This job has already been completed',
+ );
expect(web3Service.getSigner).toHaveBeenCalledWith(chainId);
});
it('should fail if user has already submitted a solution', async () => {
- const solution = 'job-solution';
+ const manifest: ManifestDto = {
+ requesterTitle: 'Example Title',
+ requesterDescription: 'Example Description',
+ submissionsRequired: 5,
+ fundAmount: 100,
+ };
+
+ assignment.status = AssignmentStatus.ACTIVE;
jest
- .spyOn(assignmentRepository, 'findOneByEscrowAndWorker')
+ .spyOn(assignmentRepository, 'findOneById')
.mockResolvedValue(assignment as AssignmentEntity);
- (EscrowClient.build as any).mockImplementation(() => ({
- getRecordingOracleAddress: jest
- .fn()
- .mockResolvedValue('0x1234567890123456789012345678901234567893'),
- }));
- OperatorUtils.getLeader = jest.fn().mockResolvedValue({
- webhookUrl: 'https://example.com/recordingoracle',
- });
-
- storageService.downloadJobSolutions = jest.fn().mockResolvedValue([
+ storageService.downloadJobSolutions = jest.fn().mockResolvedValueOnce([
{
- exchangeAddress: '0x1234567890123456789012345678901234567892',
- workerAddress: '0x1234567890123456789012345678901234567891',
+ workerAddress: workerAddress,
solution: 'test',
},
]);
- await expect(
- jobService.solveJob(chainId, escrowAddress, workerAddress, solution),
- ).rejects.toThrow('User has already submitted a solution');
+ StorageClient.downloadFileFromUrl = jest
+ .fn()
+ .mockResolvedValueOnce(manifest);
+
+ (Encryption.build as any).mockImplementation(() => ({
+ decrypt: jest.fn().mockResolvedValue(JSON.stringify(manifest)),
+ }));
+
+ await expect(jobService.solveJob(1, 'solution')).rejects.toThrow(
+ new BadRequestException(ErrorJob.SolutionAlreadySubmitted),
+ );
expect(web3Service.getSigner).toHaveBeenCalledWith(chainId);
});
});
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.ts
index cabfc81e71..20062368dc 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/job/job.service.ts
@@ -12,11 +12,11 @@ import {
Logger,
NotFoundException,
} from '@nestjs/common';
-import { ethers } from 'ethers';
import { TOKEN } from '../../common/constant';
import {
AssignmentStatus,
JobFieldName,
+ JobSortField,
JobStatus,
JobType,
} from '../../common/enums/job';
@@ -33,7 +33,9 @@ import { JobEntity } from './job.entity';
import { JobRepository } from './job.repository';
import { AssignmentRepository } from '../assignment/assignment.repository';
import { PGPConfigService } from '../../common/config/pgp-config.service';
-import { ErrorJob } from '../../common/constant/errors';
+import { ErrorJob, ErrorAssignment } from '../../common/constant/errors';
+import { SortDirection } from '../../common/enums/collection';
+import { AssignmentEntity } from '../assignment/assignment.entity';
@Injectable()
export class JobService {
@@ -74,6 +76,56 @@ export class JobService {
await this.jobRepository.createUnique(newJobEntity);
}
+ public async completeJob(webhook: WebhookDto): Promise {
+ const { chainId, escrowAddress } = webhook;
+
+ const jobEntity =
+ await this.jobRepository.findOneByChainIdAndEscrowAddressWithAssignments(
+ chainId,
+ escrowAddress,
+ );
+
+ if (!jobEntity) {
+ throw new NotFoundException(ErrorJob.NotFound);
+ }
+
+ if (jobEntity.status === JobStatus.COMPLETED) {
+ throw new BadRequestException(ErrorJob.AlreadyCompleted);
+ }
+
+ jobEntity.status = JobStatus.COMPLETED;
+ jobEntity.assignments.forEach((assignment: AssignmentEntity) => {
+ assignment.status = AssignmentStatus.COMPLETED;
+ });
+
+ await this.jobRepository.save(jobEntity);
+ }
+
+ public async cancelJob(webhook: WebhookDto): Promise {
+ const { chainId, escrowAddress } = webhook;
+
+ const jobEntity =
+ await this.jobRepository.findOneByChainIdAndEscrowAddressWithAssignments(
+ chainId,
+ escrowAddress,
+ );
+
+ if (!jobEntity) {
+ throw new NotFoundException(ErrorJob.NotFound);
+ }
+
+ if (jobEntity.status === JobStatus.CANCELED) {
+ throw new BadRequestException(ErrorJob.AlreadyCanceled);
+ }
+
+ jobEntity.status = JobStatus.CANCELED;
+ jobEntity.assignments.forEach((assignment: AssignmentEntity) => {
+ assignment.status = AssignmentStatus.CANCELED;
+ });
+
+ await this.jobRepository.save(jobEntity);
+ }
+
public async getJobList(
data: GetJobsDto,
reputationNetwork: string,
@@ -96,64 +148,80 @@ export class JobService {
entity.status,
);
- if (data.fields) {
- if (data.fields.includes(JobFieldName.CreatedAt)) {
- job.createdAt = entity.createdAt.toISOString();
+ if (data.fields?.includes(JobFieldName.CreatedAt)) {
+ job.createdAt = entity.createdAt.toISOString();
+ }
+ if (data.fields?.includes(JobFieldName.UpdatedAt)) {
+ job.updatedAt = entity.updatedAt.toISOString();
+ }
+ if (
+ data.fields?.includes(JobFieldName.JobDescription) ||
+ data.fields?.includes(JobFieldName.RewardAmount) ||
+ data.fields?.includes(JobFieldName.RewardToken) ||
+ data.sortField === JobSortField.REWARD_AMOUNT
+ ) {
+ const manifest = await this.getManifest(
+ entity.chainId,
+ entity.escrowAddress,
+ );
+ if (data.fields?.includes(JobFieldName.JobDescription)) {
+ job.jobDescription = manifest.requesterDescription;
}
if (
- data.fields.includes(JobFieldName.JobDescription) ||
- data.fields.includes(JobFieldName.RewardAmount) ||
- data.fields.includes(JobFieldName.RewardToken)
+ data.fields?.includes(JobFieldName.RewardAmount) ||
+ data.sortField === JobSortField.REWARD_AMOUNT
) {
- const manifest = await this.getManifest(
- entity.chainId,
- entity.escrowAddress,
- );
- if (data.fields.includes(JobFieldName.JobDescription)) {
- job.jobDescription = manifest.requesterDescription;
- }
- if (data.fields.includes(JobFieldName.RewardAmount)) {
- job.rewardAmount =
- manifest.fundAmount / manifest.submissionsRequired;
- }
- if (data.fields.includes(JobFieldName.RewardToken)) {
- job.rewardToken = TOKEN;
- }
+ job.rewardAmount =
+ manifest.fundAmount / manifest.submissionsRequired;
+ }
+ if (data.fields?.includes(JobFieldName.RewardToken)) {
+ job.rewardToken = TOKEN;
}
}
return job;
}),
);
+
+ if (data.sortField === JobSortField.REWARD_AMOUNT) {
+ jobs.sort((a, b) => {
+ const rewardA = a.rewardAmount ?? 0;
+ const rewardB = b.rewardAmount ?? 0;
+ if (data.sort === SortDirection.DESC) {
+ return rewardB - rewardA;
+ } else {
+ return rewardA - rewardB;
+ }
+ });
+ }
+
return new PageDto(data.page!, data.pageSize!, itemCount, jobs);
}
- public async solveJob(
- chainId: number,
- escrowAddress: string,
- workerAddress: string,
- solution: string,
- ): Promise {
- if (!ethers.isAddress(escrowAddress)) {
- throw new BadRequestException(ErrorJob.InvalidAddress);
+ public async solveJob(assignmentId: number, solution: string): Promise {
+ const assignment =
+ await this.assignmentRepository.findOneById(assignmentId);
+ if (!assignment) {
+ throw new BadRequestException(ErrorAssignment.NotFound);
}
- const assignment = await this.assignmentRepository.findOneByEscrowAndWorker(
- escrowAddress,
- workerAddress,
- );
- if (!assignment) {
- throw new BadRequestException(ErrorJob.NotAssigned);
+ if (assignment.status !== AssignmentStatus.ACTIVE) {
+ throw new BadRequestException(ErrorAssignment.InvalidStatus);
}
- await this.addSolution(chainId, escrowAddress, workerAddress, solution);
+ await this.addSolution(
+ assignment.job.chainId,
+ assignment.job.escrowAddress,
+ assignment.workerAddress,
+ solution,
+ );
assignment.status = AssignmentStatus.VALIDATION;
await this.assignmentRepository.updateOne(assignment);
const webhook = new WebhookEntity();
- webhook.escrowAddress = escrowAddress;
- webhook.chainId = chainId;
+ webhook.escrowAddress = assignment.job.escrowAddress;
+ webhook.chainId = assignment.job.chainId;
webhook.eventType = EventType.SUBMISSION_IN_REVIEW;
await this.webhookRepository.createUnique(webhook);
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.dto.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.dto.ts
index 3f175e80a3..51dfe38f66 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.dto.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.dto.ts
@@ -1,6 +1,21 @@
import { ApiProperty } from '@nestjs/swagger';
export class OracleStatsDto {
+ @ApiProperty({
+ name: 'active_escrows',
+ })
+ activeEscrows: number;
+
+ @ApiProperty({
+ name: 'completed_escrows',
+ })
+ completedEscrows: number;
+
+ @ApiProperty({
+ name: 'canceled_escrows',
+ })
+ canceledEscrows: number;
+
@ApiProperty({
name: 'workers_total',
})
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.module.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.module.ts
index 86dd695523..a0cf846a26 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.module.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.module.ts
@@ -3,13 +3,14 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { AssignmentEntity } from '../assignment/assignment.entity';
import { StatsService } from './stats.service';
import { StatsController } from './stats.controller';
+import { JobRepository } from '../job/job.repository';
import { AssignmentRepository } from '../assignment/assignment.repository';
import { ConfigModule } from '@nestjs/config';
@Module({
imports: [TypeOrmModule.forFeature([AssignmentEntity]), ConfigModule],
controllers: [StatsController],
- providers: [StatsService, AssignmentRepository],
+ providers: [StatsService, AssignmentRepository, JobRepository],
exports: [StatsService],
})
export class StatsModule {}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.spec.ts
index 2adddf90a5..0f245c248b 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.spec.ts
@@ -1,12 +1,14 @@
import { createMock } from '@golevelup/ts-jest';
import { Test } from '@nestjs/testing';
import { StatsService } from './stats.service';
+import { JobRepository } from '../job/job.repository';
import { AssignmentRepository } from '../assignment/assignment.repository';
jest.mock('../../common/utils/signature');
describe('statsService', () => {
let statsService: StatsService;
+ let jobRepository: JobRepository;
let assignmentRepository: AssignmentRepository;
const userAddress = '0x1234567890123456789012345678901234567890';
@@ -15,6 +17,10 @@ describe('statsService', () => {
imports: [],
controllers: [StatsService],
providers: [
+ {
+ provide: JobRepository,
+ useValue: createMock(),
+ },
{
provide: AssignmentRepository,
useValue: createMock(),
@@ -23,6 +29,7 @@ describe('statsService', () => {
}).compile();
statsService = moduleRef.get(StatsService);
+ jobRepository = moduleRef.get(JobRepository);
assignmentRepository =
moduleRef.get(AssignmentRepository);
});
@@ -30,6 +37,7 @@ describe('statsService', () => {
describe('getOracleStats', () => {
it('should call assignmentRepository', async () => {
await statsService.getOracleStats();
+ expect(jobRepository.countJobsByStatus).toHaveBeenCalledTimes(3);
expect(assignmentRepository.countTotalWorkers).toHaveBeenCalledWith();
expect(
assignmentRepository.countCompletedAssignments,
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.ts
index ff62f4d9d0..6233a832a3 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/stats/stats.service.ts
@@ -1,14 +1,28 @@
import { Injectable, Logger } from '@nestjs/common';
+import { JobRepository } from '../job/job.repository';
import { AssignmentRepository } from '../assignment/assignment.repository';
import { AssignmentStatsDto, OracleStatsDto } from './stats.dto';
+import { JobStatus } from '../../common/enums/job';
@Injectable()
export class StatsService {
public readonly logger = new Logger(StatsService.name);
- constructor(private assignmentRepository: AssignmentRepository) {}
+ constructor(
+ private jobRepository: JobRepository,
+ private assignmentRepository: AssignmentRepository,
+ ) {}
async getOracleStats(): Promise {
return new OracleStatsDto({
+ activeEscrows: await this.jobRepository.countJobsByStatus(
+ JobStatus.ACTIVE,
+ ),
+ completedEscrows: await this.jobRepository.countJobsByStatus(
+ JobStatus.COMPLETED,
+ ),
+ canceledEscrows: await this.jobRepository.countJobsByStatus(
+ JobStatus.CANCELED,
+ ),
workersTotal: await this.assignmentRepository.countTotalWorkers(),
assignmentsCompleted:
await this.assignmentRepository.countCompletedAssignments(),
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.spec.ts
index ff78a09b76..0bed477033 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.spec.ts
@@ -5,6 +5,7 @@ import { EventType } from '../../common/enums/webhook';
import { WebhookController } from './webhook.controller';
import { WebhookDto } from './webhook.dto';
import { WebhookService } from './webhook.service';
+import { AssignmentRepository } from '../assignment/assignment.repository';
jest.mock('../../common/utils/signature');
@@ -20,6 +21,10 @@ describe('webhookController', () => {
controllers: [WebhookController],
providers: [
{ provide: WebhookService, useValue: createMock() },
+ {
+ provide: AssignmentRepository,
+ useValue: createMock(),
+ },
],
}).compile();
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.ts
index d987483662..e3d0fe8981 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.controller.ts
@@ -6,23 +6,25 @@ import {
ApiOperation,
ApiTags,
} from '@nestjs/swagger';
-import { Role } from '../../common/enums/role';
+import { AuthSignatureRole } from '../../common/enums/role';
import { SignatureAuthGuard } from '../../common/guards';
import { WebhookService } from './webhook.service';
import { HEADER_SIGNATURE_KEY } from '../../common/constant';
import { WebhookDto } from './webhook.dto';
-import { Public } from '../../common/decorators';
+import { AllowedRoles } from '../../common/decorators/role';
-@Public()
@ApiTags('Webhook')
@Controller('/webhook')
export class WebhookController {
constructor(private readonly webhookService: WebhookService) {}
@Post()
- @UseGuards(
- new SignatureAuthGuard([Role.Recording, Role.Reputation, Role.JobLauncher]),
- )
+ @UseGuards(SignatureAuthGuard)
+ @AllowedRoles([
+ AuthSignatureRole.Recording,
+ AuthSignatureRole.Reputation,
+ AuthSignatureRole.JobLauncher,
+ ])
@ApiOperation({
summary: 'Handle Webhook Events',
description:
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.module.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.module.ts
index 6e627edf55..25c1720873 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.module.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.module.ts
@@ -10,18 +10,22 @@ import { WebhookEntity } from './webhook.entity';
import { HttpModule } from '@nestjs/axios';
import { Web3Module } from '../web3/web3.module';
import { StorageModule } from '../storage/storage.module';
+import { AssignmentModule } from '../assignment/assignment.module';
+import { AssignmentRepository } from '../assignment/assignment.repository';
+import { AssignmentEntity } from '../assignment/assignment.entity';
@Module({
imports: [
- TypeOrmModule.forFeature([WebhookEntity]),
+ TypeOrmModule.forFeature([WebhookEntity, AssignmentEntity]),
JobModule,
Web3Module,
ConfigModule,
HttpModule,
StorageModule,
+ AssignmentModule,
],
controllers: [WebhookController],
- providers: [Logger, WebhookService, WebhookRepository],
+ providers: [Logger, WebhookService, WebhookRepository, AssignmentRepository],
exports: [WebhookService],
})
export class WebhookModule {}
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts
index 4396581ac9..a68fcc0423 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.spec.ts
@@ -131,12 +131,14 @@ describe('WebhookService', () => {
});
it('should handle an incoming escrow canceled webhook', async () => {
+ jest.spyOn(jobService, 'cancelJob').mockResolvedValue();
const webhook: WebhookDto = {
chainId,
escrowAddress,
eventType: EventType.ESCROW_CANCELED,
};
expect(await webhookService.handleWebhook(webhook)).toBe(undefined);
+ expect(jobService.cancelJob).toHaveBeenCalledWith(webhook);
});
it('should mark a job solution as invalid', async () => {
diff --git a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts
index 851ce9559e..acde287478 100644
--- a/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts
+++ b/packages/apps/fortune/exchange-oracle/server/src/modules/webhook/webhook.service.ts
@@ -37,22 +37,27 @@ export class WebhookService {
public readonly storageService: StorageService,
) {}
- public async handleWebhook(wehbook: WebhookDto): Promise {
- switch (wehbook.eventType) {
+ public async handleWebhook(webhook: WebhookDto): Promise {
+ switch (webhook.eventType) {
case EventType.ESCROW_CREATED:
- await this.jobService.createJob(wehbook);
+ await this.jobService.createJob(webhook);
+ break;
+
+ case EventType.ESCROW_COMPLETED:
+ await this.jobService.completeJob(webhook);
break;
case EventType.ESCROW_CANCELED:
+ await this.jobService.cancelJob(webhook);
break;
case EventType.SUBMISSION_REJECTED:
- await this.jobService.processInvalidJobSolution(wehbook);
+ await this.jobService.processInvalidJobSolution(webhook);
break;
default:
throw new BadRequestException(
- `Invalid webhook event type: ${wehbook.eventType}`,
+ `Invalid webhook event type: ${webhook.eventType}`,
);
}
}
diff --git a/packages/apps/fortune/exchange-oracle/server/test/setup.ts b/packages/apps/fortune/exchange-oracle/server/test/setup.ts
index 9f2c592e2e..4680ef7809 100644
--- a/packages/apps/fortune/exchange-oracle/server/test/setup.ts
+++ b/packages/apps/fortune/exchange-oracle/server/test/setup.ts
@@ -1,6 +1,7 @@
import { KVStoreClient, KVStoreKeys, Role } from '@human-protocol/sdk';
import { Wallet, ethers } from 'ethers';
import * as dotenv from 'dotenv';
+import * as Minio from 'minio';
dotenv.config({ path: '.env.local' });
export async function setup(): Promise {
@@ -15,7 +16,45 @@ export async function setup(): Promise {
await kvStoreClient.setBulk(
[KVStoreKeys.role, KVStoreKeys.fee, KVStoreKeys.webhookUrl],
[Role.ExchangeOracle, '1', 'http://localhost:5001/webhook'],
+ { nonce: 0 },
);
+
+ if (process.env.PGP_ENCRYPT && process.env.PGP_ENCRYPT === 'true') {
+ if (!process.env.PGP_PUBLIC_KEY) {
+ throw new Error('PGP public key is empty');
+ }
+ const minioClient = new Minio.Client({
+ endPoint: process.env.S3_ENDPOINT || 'localhost',
+ port: parseInt(process.env.S3_PORT || '9000', 10),
+ useSSL: process.env.S3_USE_SSL === 'true',
+ accessKey: process.env.S3_ACCESS_KEY || 'access-key',
+ secretKey: process.env.S3_SECRET_KEY || 'secret-key',
+ });
+ const bucket = process.env.S3_BUCKET || 'bucket';
+ const fileName = 'exo-pgp-public-key.txt';
+ const exists = await minioClient.bucketExists(bucket);
+ if (!exists) {
+ throw new Error('Bucket does not exists');
+ }
+ try {
+ await minioClient.putObject(
+ bucket,
+ fileName,
+ process.env.PGP_PUBLIC_KEY,
+ {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-store',
+ },
+ );
+ await kvStoreClient.setFileUrlAndHash(
+ `http://localhost:9000/bucket/${fileName}`,
+ KVStoreKeys.publicKey,
+ { nonce: 1 },
+ );
+ } catch (e) {
+ console.log(e);
+ }
+ }
}
setup();
diff --git a/packages/apps/fortune/exchange-oracle/server/typeorm.config.ts b/packages/apps/fortune/exchange-oracle/server/typeorm.config.ts
index d636d85e2f..040b3c1c94 100644
--- a/packages/apps/fortune/exchange-oracle/server/typeorm.config.ts
+++ b/packages/apps/fortune/exchange-oracle/server/typeorm.config.ts
@@ -15,7 +15,7 @@ export default new DataSource({
port: Number(process.env.POSTGRES_PORT),
username: process.env.POSTGRES_USER,
password: process.env.POSTGRES_PASSWORD,
- database: process.env.POSTGRES_DATABASE,
+ database: process.env.POSTGRES_DATABASE || 'exchange-oracle',
entities: ['dist/src/**/*.entity{.ts,.js}'],
synchronize: false,
migrations: ['dist/src/database/migrations/*{.ts,.js}'],
diff --git a/packages/apps/fortune/package.json b/packages/apps/fortune/package.json
deleted file mode 100644
index 657e44cd67..0000000000
--- a/packages/apps/fortune/package.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "private": "true",
- "name": "@human-protocol/fortune-v3",
- "version": "1.0.0",
- "description": "Human Protocol Fortune",
- "license": "MIT",
- "scripts": {
- "recording-oracle:dev": "cd recording-oracle && yarn start:dev",
- "recording-oracle:lint": "cd recording-oracle && yarn lint",
- "recording-oracle:test": "cd recording-oracle && yarn test",
- "lint": "concurrently npm:recording-oracle:lint",
- "lint:fix": "concurrently npm:recording-oracle:lint:fix",
- "pretest": "yarn workspace @human-protocol/sdk build",
- "test": "concurrently npm:recording-oracle:test"
- }
-}
diff --git a/packages/apps/fortune/recording-oracle/README.md b/packages/apps/fortune/recording-oracle/README.md
index ed99b4289e..e8d16bd3c5 100644
--- a/packages/apps/fortune/recording-oracle/README.md
+++ b/packages/apps/fortune/recording-oracle/README.md
@@ -1,33 +1,76 @@
-# Recording Oracle Server for Fortune App
+
+
+
-The Fortune Recording Oracle application works directly with the results from Exchange Oracle, validating them and recording them to a file.
+[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
+[circleci-url]: https://circleci.com/gh/nestjs/nest
-## API
+Fortune Recording Oracle
+ Recording Oracle application works directly with the results from Exchange Oracle, validating them and recording them to a file.
-- POST `/job/solve`
+
+
+
+
+
- Submits a solution from exchange oracle.
+
- Request Payload:
+## ✨ Demo
- ```json
- {
- "escrowAddress": string,
- "chainId": number,
- "exchangeAddress": string,
- "workerAddress": string,
- "solution": string
- }
- ```
+First, let's install the dependencies, `yarn` is used as a package manager:
-## Development
+```bash
+$ yarn install
+```
-- Install dependencies with `yarn`.
-- Run minio docker container.
- ```bash
- cd ..
- docker compose up
- ```
-- Run dev server with `yarn start:dev`.
+The application needs access to environment variables in order to work correctly, for this, create one of the `.env.` files, depending on the state of your environment:
-## Deployment
+```bash
+$ export NODE_ENV=development
+```
+
+Use the `.env.example` file as an example to create a configuration file with certain environment variables:
+
+```bash
+$ cp .env.example .env.development
+```
+
+## 🚀 Usage
+
+### Running the app
+
+```bash
+# development
+$ yarn run start
+
+# watch mode
+$ yarn run start:dev
+
+# production mode
+$ yarn run start:prod
+
+# debug mode
+$ yarn run start:debug
+```
+
+### Testing the app
+
+```bash
+# unit tests
+$ yarn run test
+
+# e2e tests
+$ yarn run test:e2e
+
+# test coverage
+$ yarn run test:cov
+```
+
+## 📚 Documentation
+
+For detailed information about the Recording Oracle, please refer to the [Human Protocol Tech Docs](https://human-protocol.gitbook.io/hub/human-tech-docs/architecture/components/recording-oracle).
+
+## 📝 License
+
+This project is licensed under the MIT License. See the [LICENSE](https://github.com/humanprotocol/human-protocol/blob/main/LICENSE) file for details.
diff --git a/packages/apps/fortune/recording-oracle/package.json b/packages/apps/fortune/recording-oracle/package.json
index b4513a368c..f88b977f41 100644
--- a/packages/apps/fortune/recording-oracle/package.json
+++ b/packages/apps/fortune/recording-oracle/package.json
@@ -24,21 +24,19 @@
},
"dependencies": {
"@human-protocol/sdk": "*",
- "@nestjs/axios": "^2.0.0",
+ "@nestjs/axios": "^3.0.2",
"@nestjs/common": "^10.2.7",
"@nestjs/config": "^3.1.1",
- "@nestjs/core": "^10.2.8",
- "@nestjs/platform-express": "^10.3.8",
+ "@nestjs/core": "^10.3.10",
"@nestjs/swagger": "^7.1.13",
"body-parser": "^1.20.2",
"class-validator": "^0.14.1",
- "cookie-parser": "^1.4.6",
"helmet": "^7.1.0",
- "reflect-metadata": "^0.1.13"
+ "reflect-metadata": "^0.2.2"
},
"devDependencies": {
"@nestjs/cli": "^10.3.2",
- "@nestjs/schematics": "^9.2.0",
+ "@nestjs/schematics": "^10.1.3",
"@nestjs/testing": "^10.3.1",
"@types/express": "^4.17.13"
}
diff --git a/packages/apps/fortune/recording-oracle/src/main.ts b/packages/apps/fortune/recording-oracle/src/main.ts
index 32da0466fa..369cf35591 100644
--- a/packages/apps/fortune/recording-oracle/src/main.ts
+++ b/packages/apps/fortune/recording-oracle/src/main.ts
@@ -2,8 +2,6 @@ import { NestFactory } from '@nestjs/core';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import { json, urlencoded } from 'body-parser';
import { useContainer } from 'class-validator';
-import cookieParser from 'cookie-parser';
-import session from 'express-session';
import helmet from 'helmet';
import { INestApplication } from '@nestjs/common';
@@ -22,7 +20,6 @@ async function bootstrap() {
const host = serverConfigService.host;
const port = serverConfigService.port;
- const sessionSecret = serverConfigService.sessionSecret;
app.useGlobalFilters(new GlobalExceptionsFilter());
@@ -34,18 +31,6 @@ async function bootstrap() {
useContainer(app.select(AppModule), { fallbackOnErrors: true });
- app.use(cookieParser());
-
- app.use(
- session({
- secret: sessionSecret,
- resave: false,
- saveUninitialized: false,
- cookie: {
- secure: true,
- },
- }),
- );
app.use(json({ limit: '5mb' }));
app.use(urlencoded({ limit: '5mb', extended: true }));
diff --git a/packages/apps/fortune/recording-oracle/test/setup.ts b/packages/apps/fortune/recording-oracle/test/setup.ts
index cdba2d9bb2..6c9e5348be 100644
--- a/packages/apps/fortune/recording-oracle/test/setup.ts
+++ b/packages/apps/fortune/recording-oracle/test/setup.ts
@@ -1,6 +1,7 @@
import { KVStoreClient, KVStoreKeys, Role } from '@human-protocol/sdk';
import { Wallet, ethers } from 'ethers';
import * as dotenv from 'dotenv';
+import * as Minio from 'minio';
dotenv.config({ path: '.env.local' });
export async function setup(): Promise {
@@ -15,7 +16,50 @@ export async function setup(): Promise {
await kvStoreClient.setBulk(
[KVStoreKeys.role, KVStoreKeys.fee, KVStoreKeys.webhookUrl],
[Role.RecordingOracle, '1', 'http://localhost:5002/webhook'],
+ {
+ nonce: 0,
+ },
);
+
+ if (process.env.PGP_ENCRYPT && process.env.PGP_ENCRYPT === 'true') {
+ if (!process.env.PGP_PUBLIC_KEY) {
+ throw new Error('PGP public key is empty');
+ }
+ const minioClient = new Minio.Client({
+ endPoint: process.env.S3_ENDPOINT || 'localhost',
+ port: parseInt(process.env.S3_PORT || '9000', 10),
+ useSSL: process.env.S3_USE_SSL === 'true',
+ accessKey: process.env.S3_ACCESS_KEY || 'access-key',
+ secretKey: process.env.S3_SECRET_KEY || 'secret-key',
+ });
+ const bucket = process.env.S3_BUCKET || 'bucket';
+ const fileName = 'reco-pgp-public-key.txt';
+ const exists = await minioClient.bucketExists(bucket);
+ if (!exists) {
+ throw new Error('Bucket does not exists');
+ }
+ try {
+ await minioClient.putObject(
+ bucket,
+ fileName,
+ process.env.PGP_PUBLIC_KEY,
+ {
+ 'Content-Type': 'application/json',
+ 'Cache-Control': 'no-store',
+ },
+ );
+ await kvStoreClient.setFileUrlAndHash(
+ `http://localhost:9000/bucket/${fileName}`,
+ KVStoreKeys.publicKey,
+ {
+ nonce: 1,
+ },
+ );
+ } catch (e) {
+ // eslint-disable-next-line no-console
+ console.log(e);
+ }
+ }
}
setup();
diff --git a/packages/apps/human-app/frontend/.env.example b/packages/apps/human-app/frontend/.env.example
new file mode 100644
index 0000000000..b60b85ac5e
--- /dev/null
+++ b/packages/apps/human-app/frontend/.env.example
@@ -0,0 +1,66 @@
+# api url
+VITE_API_URL= #string
+# link to privacy policy page
+VITE_PRIVACY_POLICY_URL= #string
+# link to terms of service
+VITE_TERMS_OF_SERVICE_URL= #string
+# link to help page
+VITE_HUMAN_PROTOCOL_HELP_URL= #string
+# link to human web page
+VITE_HUMAN_PROTOCOL_URL= #string
+# link to "Learn more" in wallet connect modal
+VITE_WALLET_CONNECT_MODAL_LINK= #string
+# link to human web page in main page navbar
+VITE_NAVBAR__LINK__PROTOCOL_URL= #string
+# link to human web page section in main page navbar
+VITE_NAVBAR__LINK__HOW_IT_WORK_URL= #string
+# capthca site key for captcha other than labeling
+VITE_H_CAPTCHA_SITE_KEY= #string
+# HMT daily spent limit
+VITE_HMT_DAILY_SPENT_LIMIT= #number
+# daily solved captcha limit
+VITE_DAILY_SOLVED_CAPTCHA_LIMIT= #number
+# capthca url for captcha other than labeling
+VITE_H_CAPTCHA_EXCHANGE_URL= #string
+# capthca url for labeling
+VITE_H_CAPTCHA_LABELING_BASE_URL= #string
+# ID of project created with https://cloud.walletconnect.com/sign-in
+VITE_WALLET_CONNECT_PROJECT_ID= #string
+# Dapp name for wallet connect
+VITE_DAPP_META_NAME= #string
+# Dapp description for wallet connect
+VITE_DAPP_META_DESCRIPTION= #string
+# Dapp url for wallet connect
+VITE_DAPP_META_URL= #string
+# Dapp icons for wallet connect
+VITE_DAPP_ICONS= #string => lists of icons eg.: icon1,icon2...
+
+# network if network is equl to 'testnet' app will use first tesntet chain from .src/smart-contracts/chains.ts
+# and first mainnet chain for 'mainnet'
+VITE_NETWORK= # mainnet|testnet
+
+## Web3 setup
+# set SC addresses according to https://human-protocol.gitbook.io/hub/human-tech-docs/architecture/components/smart-contracts/contract-addresses
+
+## testnet
+
+# Amoy
+VITE_TESTNET_AMOY_STAKING_CONTRACT=
+VITE_TESTNET_AMOY_HMTOKEN_CONTRACT=
+VITE_TESTNET_AMOY_ETH_KV_STORE_CONTRACT=
+
+## mainnet
+
+# Polygon
+VITE_MAINNET_POLYGON_STAKING_CONTRACT=
+VITE_MAINNET_POLYGON_HMTOKEN_CONTRACT=
+VITE_MAINNET_POLYGON_ETH_KV_STORE_CONTRACT=
+
+## other networks
+# if you wish to add new network follow this instruction:
+# - add your env-s set to .env file
+# - add new env-s to validation schema in: ./src/shared/env.ts
+# - include new valid env-s in: ./src/smart-contracts/contracts.ts
+# - add chain data in: .src/smart-contracts/chains.ts
+
+# all new chains will be available in wallet-connect modal
\ No newline at end of file
diff --git a/packages/apps/human-app/frontend/.eslintrc.cjs b/packages/apps/human-app/frontend/.eslintrc.cjs
new file mode 100644
index 0000000000..101084ca76
--- /dev/null
+++ b/packages/apps/human-app/frontend/.eslintrc.cjs
@@ -0,0 +1,48 @@
+const { resolve } = require('node:path');
+
+const project = resolve(__dirname, 'tsconfig.json');
+
+module.exports = {
+ root: true,
+ extends: [
+ require.resolve('@vercel/style-guide/eslint/browser'),
+ require.resolve('@vercel/style-guide/eslint/typescript'),
+ require.resolve('@vercel/style-guide/eslint/react'),
+ 'plugin:prettier/recommended',
+ 'plugin:@tanstack/eslint-plugin-query/recommended',
+ ],
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
+ parserOptions: {
+ ecmaVersion: 'latest',
+ sourceType: 'module',
+ project: ['./tsconfig.json', './tsconfig.node.json'],
+ tsconfigRootDir: __dirname,
+ },
+ plugins: ['react-refresh'],
+ rules: {
+ 'react-refresh/only-export-components': [
+ 'warn',
+ { allowConstantExport: true },
+ ],
+ 'import/extensions': [
+ 'error',
+ 'ignorePackages',
+ {
+ ts: 'never',
+ tsx: 'never',
+ },
+ ],
+ 'eslint-comments/require-description': 'off',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ // allow imports from material react table library
+ camelcase: ['error', { allow: ['MRT_'] }],
+ 'react/jsx-pascal-case': ['error', { ignore: ['MRT_'] }],
+ },
+ settings: {
+ 'import/resolver': {
+ typescript: {
+ project,
+ },
+ },
+ },
+};
diff --git a/packages/apps/human-app/frontend/.gitignore b/packages/apps/human-app/frontend/.gitignore
new file mode 100644
index 0000000000..95e166699d
--- /dev/null
+++ b/packages/apps/human-app/frontend/.gitignore
@@ -0,0 +1,28 @@
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
+
+# Editor directories and files
+.vscode/*
+!.vscode/extensions.json
+!.vscode/settings.json
+.idea
+.DS_Store
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw?
+
+.env
+.env.local
\ No newline at end of file
diff --git a/packages/apps/human-app/frontend/.husky/pre-commit b/packages/apps/human-app/frontend/.husky/pre-commit
new file mode 100644
index 0000000000..2312dc587f
--- /dev/null
+++ b/packages/apps/human-app/frontend/.husky/pre-commit
@@ -0,0 +1 @@
+npx lint-staged
diff --git a/packages/apps/human-app/frontend/.prettierrc b/packages/apps/human-app/frontend/.prettierrc
new file mode 100644
index 0000000000..dd7fe55198
--- /dev/null
+++ b/packages/apps/human-app/frontend/.prettierrc
@@ -0,0 +1,7 @@
+{
+ "trailingComma": "es5",
+ "semi": true,
+ "singleQuote": true,
+ "tabWidth": 2,
+ "endOfLine": "lf"
+}
diff --git a/packages/apps/human-app/frontend/README.md b/packages/apps/human-app/frontend/README.md
new file mode 100644
index 0000000000..4de4364a28
--- /dev/null
+++ b/packages/apps/human-app/frontend/README.md
@@ -0,0 +1,90 @@
+# Human app - Frontend
+
+## Build With
+
+| Tool-Name | Description |
+| ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- |
+| [ESlint](https://github.com/vercel/style-guide) with [Prettier plugin](https://github.com/prettier/eslint-plugin-prettier) | Linting and Formatting |
+| [ESlint Vercel style guide](https://github.com/vercel/style-guide) | eslint config preset |
+| [Husky](https://typicode.github.io/husky/get-started.html) with [lint-staged](https://github.com/lint-staged/lint-staged?tab=readme-ov-file#-lint-staged----) | pre-commit |
+| [TypeScript](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html) | Static typing |
+| [Vite](https://vitejs.dev/guide/why.html) | Bundler |
+| [React](https://react.dev/learn/describing-the-ui) | Frontend Framework |
+| [React Router](https://reactrouter.com/en/main/start/tutorial) | Client Side Routing |
+| [TanStack Query](https://tanstack.com/query/latest/docs/framework/react/overview) | Async state management |
+| [Material UI](https://mui.com/material-ui/getting-started/) | UI Components |
+| [Material Icons](https://mui.com/material-ui/material-icons/) | Icons |
+| [Material React Table](https://www.material-react-table.com/about) | Table component for material ui |
+| [Zod](https://github.com/colinhacks/zod?tab=readme-ov-file#table-of-contents) | Runtime Validations |
+| [i18next](https://react.i18next.com/getting-started) | Internationalization Framework |
+
+## Getting Started
+
+### Prerequisites
+
+- [Node.js minimal v18](https://nodejs.org/en)
+- [pnpm](https://pnpm.io/installation)
+
+### Install Packages
+
+```sh
+yarn install
+```
+
+### Compile and Hot-Reload for Development
+
+```sh
+yarn dev
+```
+
+### Type-Check, Compile and Minify for Production
+
+```sh
+yarn build
+```
+
+### Linting and Formatting
+
+```sh
+yarn lint
+```
+
+### Tests
+
+```sh
+yarn test
+```
+
+## Web3 setup
+
+The Web3 setup is closely tied to contract addresses. The best explanation for this can be found in the `.env.example` file, which shows where to set your smart contract addresses.
+
+`.env.example`
+```
+...
+## Web3 setup
+# set SC addresses according to https://human-protocol.gitbook.io/hub/human-tech-docs/architecture/components/smart-contracts/contract-addresses
+
+## testnet
+
+# Amoy
+VITE_TESTNET_AMOY_STAKING_CONTRACT=
+VITE_TESTNET_AMOY_HMTOKEN_CONTRACT=
+VITE_TESTNET_AMOY_ETH_KV_STORE_CONTRACT=
+
+## mainnet
+
+# Polygon
+VITE_MAINNET_POLYGON_STAKING_CONTRACT=
+VITE_MAINNET_POLYGON_HMTOKEN_CONTRACT=
+VITE_MAINNET_POLYGON_ETH_KV_STORE_CONTRACT=
+
+## other networks
+# if you wish to add new network follow this instruction:
+# - add your env-s set to .env file
+# - add new env-s to validation schema in: ./src/shared/env.ts
+# - include new valid env-s in: ./src/smart-contracts/contracts.ts
+# - add chain data in: .src/smart-contracts/chains.ts
+
+# all new chains will be available in wallet-connect modal
+```
diff --git a/packages/apps/human-app/frontend/index.html b/packages/apps/human-app/frontend/index.html
new file mode 100644
index 0000000000..f0d7c8c0a5
--- /dev/null
+++ b/packages/apps/human-app/frontend/index.html
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+ Human App
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/package.json b/packages/apps/human-app/frontend/package.json
new file mode 100644
index 0000000000..abc1d3b0e5
--- /dev/null
+++ b/packages/apps/human-app/frontend/package.json
@@ -0,0 +1,76 @@
+{
+ "name": "@human-protocol/human-app-frontend",
+ "private": true,
+ "version": "1.0.0",
+ "scripts": {
+ "dev": "vite",
+ "build": "tsc && vite build",
+ "start:prod": "serve -s dist",
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
+ "preview": "vite preview",
+ "test": "vitest",
+ "prepare": "husky"
+ },
+ "lint-staged": {
+ "*.{ts,tsx}": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.11.3",
+ "@emotion/styled": "^11.11.0",
+ "@fontsource/inter": "^5.0.17",
+ "@hcaptcha/react-hcaptcha": "^0.3.6",
+ "@hookform/resolvers": "^3.3.4",
+ "@mui/icons-material": "^5.15.7",
+ "@mui/material": "^5.15.7",
+ "@synaps-io/verify-sdk": "^4.0.45",
+ "@tanstack/react-query": "^5.18.1",
+ "@walletconnect/ethereum-provider": "^2.12.2",
+ "@walletconnect/modal": "^2.6.2",
+ "@web3modal/ethers": "^4.1.9",
+ "@web3modal/scaffold-utils": "^4.1.11",
+ "date-fns": "^3.6.0",
+ "ethers": "^6.12.0",
+ "i18next": "^23.8.2",
+ "jwt-decode": "^4.0.0",
+ "lodash": "^4.17.21",
+ "material-react-table": "^2.12.1",
+ "mui-image": "^1.0.7",
+ "query-string": "^9.0.0",
+ "react": "^18.2.0",
+ "react-dom": "^18.2.0",
+ "react-hook-form": "^7.50.0",
+ "react-i18next": "^14.0.2",
+ "react-imask": "^7.4.0",
+ "react-number-format": "^5.3.4",
+ "react-router-dom": "^6.22.0",
+ "vite-plugin-svgr": "^4.2.0",
+ "zod": "^3.22.4",
+ "zustand": "^4.5.0"
+ },
+ "devDependencies": {
+ "@tanstack/eslint-plugin-query": "^5.18.1",
+ "@tanstack/react-query-devtools": "^5.18.1",
+ "@testing-library/jest-dom": "^6.4.2",
+ "@testing-library/react": "^14.2.1",
+ "@types/lodash": "^4.14.202",
+ "@types/mui-image": "^1.0.5",
+ "@types/node": "^20.11.16",
+ "@types/react": "^18.2.43",
+ "@types/react-dom": "^18.2.17",
+ "@typescript-eslint/eslint-plugin": "^6.20.0",
+ "@vercel/style-guide": "^5.2.0",
+ "@vitejs/plugin-react": "^4.2.1",
+ "@vitest/ui": "^1.4.0",
+ "eslint": "^8.55.0",
+ "eslint-config-prettier": "^9.1.0",
+ "eslint-plugin-prettier": "^5.1.3",
+ "eslint-plugin-react-refresh": "^0.4.5",
+ "husky": "^9.0.10",
+ "jsdom": "^24.0.0",
+ "lint-staged": "^15.2.1",
+ "prettier": "^3.2.5",
+ "typescript": "^5.2.2",
+ "vite": "^5.0.8",
+ "vitest": "^1.2.2"
+ }
+}
diff --git a/packages/apps/human-app/frontend/public/favicon.ico b/packages/apps/human-app/frontend/public/favicon.ico
new file mode 100644
index 0000000000..361e421bdc
Binary files /dev/null and b/packages/apps/human-app/frontend/public/favicon.ico differ
diff --git a/packages/apps/human-app/frontend/public/manifest.json b/packages/apps/human-app/frontend/public/manifest.json
new file mode 100644
index 0000000000..bf17e61c8b
--- /dev/null
+++ b/packages/apps/human-app/frontend/public/manifest.json
@@ -0,0 +1,15 @@
+{
+ "short_name": "Human App",
+ "name": "Human App",
+ "icons": [
+ {
+ "src": "favicon.ico",
+ "sizes": "64x64 32x32 24x24 16x16",
+ "type": "image/x-icon"
+ }
+ ],
+ "start_url": ".",
+ "display": "standalone",
+ "theme_color": "#000000",
+ "background_color": "#ffffff"
+}
diff --git a/packages/apps/human-app/frontend/src/api/api-client.ts b/packages/apps/human-app/frontend/src/api/api-client.ts
new file mode 100644
index 0000000000..f4671d4cbe
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/api-client.ts
@@ -0,0 +1,14 @@
+// eslint-disable-next-line import/no-cycle -- cause by refresh token retry
+import { createFetcher } from '@/api/fetcher';
+import { env } from '@/shared/env';
+
+export const apiClient = createFetcher({
+ baseUrl: env.VITE_API_URL,
+ options: () => {
+ const headers = new Headers({ 'Content-Type': 'application/json' });
+
+ return {
+ headers,
+ };
+ },
+});
diff --git a/packages/apps/human-app/frontend/src/api/api-paths.ts b/packages/apps/human-app/frontend/src/api/api-paths.ts
new file mode 100644
index 0000000000..0a5f301344
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/api-paths.ts
@@ -0,0 +1,75 @@
+export const apiPaths = {
+ test: {
+ path: '/test',
+ },
+ worker: {
+ signIn: {
+ path: '/auth/signin',
+ },
+ signUp: {
+ path: '/auth/signup',
+ },
+ obtainAccessToken: {
+ path: '/auth/refresh',
+ },
+ sendResetLink: {
+ path: '/password-reset/forgot-password',
+ },
+ resetPassword: {
+ path: '/password-reset/restore-password',
+ },
+ verifyEmail: {
+ path: '/email-confirmation/email-verification',
+ },
+ resendEmailVerification: {
+ path: '/email-confirmation/resend-email-verification',
+ },
+ kycSessionId: {
+ path: '/kyc/start',
+ },
+ oracles: {
+ path: '/oracles',
+ },
+ jobs: {
+ path: '/jobs',
+ },
+ myJobs: {
+ path: '/assignment/job',
+ },
+ assignJob: {
+ path: '/assignment/job',
+ },
+ resignJob: {
+ path: '/assignment/resign-job',
+ },
+ registerAddress: {
+ path: '/user/register-address',
+ },
+ signedAddress: {
+ path: '/kyc/on-chain',
+ },
+ enableHCaptchaLabeling: '/labeling/h-captcha/enable',
+ verifyHCaptchaLabeling: '/labeling/h-captcha/verify',
+ hCaptchaUserStats: '/labeling/h-captcha/user-stats',
+ dailyHmtSpend: '/labeling/h-captcha/daily-hmt-spent',
+ },
+ operator: {
+ web3Auth: {
+ prepareSignature: {
+ path: '/prepare-signature',
+ },
+ signUp: {
+ path: '/auth/web3/signup',
+ },
+ signIn: {
+ path: '/auth/web3/signin',
+ },
+ stats: {
+ path: '/stats',
+ },
+ },
+ disableOperator: {
+ path: '/disable-operator',
+ },
+ },
+} as const;
diff --git a/packages/apps/human-app/frontend/src/api/fetcher.ts b/packages/apps/human-app/frontend/src/api/fetcher.ts
new file mode 100644
index 0000000000..449a170204
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/fetcher.ts
@@ -0,0 +1,225 @@
+import merge from 'lodash/merge';
+import { ZodError, type ZodType, type ZodTypeDef } from 'zod';
+import type { ResponseError } from '@/shared/types/global.type';
+import type { SignInSuccessResponse } from '@/api/servieces/worker/sign-in';
+// eslint-disable-next-line import/no-cycle -- cause by refresh token retry
+import { signInSuccessResponseSchema } from '@/api/servieces/worker/sign-in';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { browserAuthProvider } from '@/shared/helpers/browser-auth-provider';
+
+const appendHeader = (
+ fetcherOptionsWithDefaults: RequestInit | undefined,
+ newHeaders: Record
+) => {
+ const headers = new Headers(fetcherOptionsWithDefaults?.headers);
+
+ for (const [key, value] of Object.entries(newHeaders)) {
+ headers.set(key, value);
+ }
+
+ return {
+ ...fetcherOptionsWithDefaults,
+ headers,
+ };
+};
+
+export class FetchError extends Error {
+ status: number;
+ data: unknown;
+
+ constructor({
+ message,
+ data,
+ status,
+ }: {
+ message: string;
+ status: number;
+ data: unknown;
+ }) {
+ super(message);
+ this.status = status;
+ this.data = data;
+ }
+}
+
+export type FetcherOptionsWithValidation =
+ Readonly<{
+ options?: RequestInit;
+ successSchema: ZodType;
+ skipValidation?: false | undefined;
+ authenticated?: boolean;
+ baseUrl?: string;
+ }>;
+
+export type FetcherOptionsWithoutValidation = Readonly<{
+ options?: RequestInit;
+ skipValidation: true;
+ authenticated?: boolean;
+ baseUrl?: string;
+}>;
+
+export type FetcherOptions =
+ | FetcherOptionsWithValidation
+ | FetcherOptionsWithoutValidation;
+
+export type FetcherUrl = string | URL;
+
+export function createFetcher(defaultFetcherConfig?: {
+ options?: RequestInit | (() => RequestInit);
+ baseUrl: FetcherUrl | (() => FetcherUrl);
+}) {
+ async function fetcher(
+ url: string | URL,
+ fetcherOptions: FetcherOptionsWithValidation
+ ): Promise;
+
+ async function fetcher(
+ url: FetcherUrl,
+ fetcherOptions: FetcherOptionsWithoutValidation
+ ): Promise;
+
+ async function fetcher(
+ url: FetcherUrl,
+ fetcherOptions: FetcherOptions
+ // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents -- required unknown for correct type intellisense
+ ): Promise {
+ let fetcherOptionsWithDefaults = defaultFetcherConfig?.options
+ ? merge(
+ {},
+ (() => {
+ const options = defaultFetcherConfig.options;
+ if (options instanceof Function) return options();
+ return options;
+ })(),
+ fetcherOptions.options
+ )
+ : fetcherOptions.options;
+
+ if (fetcherOptions.authenticated) {
+ fetcherOptionsWithDefaults = appendHeader(fetcherOptionsWithDefaults, {
+ Authorization: `Bearer ${browserAuthProvider.getAccessToken()}`,
+ });
+ }
+
+ const baseUrl = (() => {
+ const currentUrl = fetcherOptions.baseUrl
+ ? () => fetcherOptions.baseUrl
+ : defaultFetcherConfig?.baseUrl;
+ if (currentUrl instanceof Function) return currentUrl();
+ return currentUrl;
+ })();
+
+ function fetchUrlToString(fetchUrl: string | URL): string;
+ function fetchUrlToString(fetchUrl: undefined): undefined;
+ function fetchUrlToString(
+ fetchUrl: string | URL | undefined
+ ): string | undefined;
+ function fetchUrlToString(
+ fetchUrl: string | URL | undefined
+ ): string | undefined {
+ if (!fetchUrl) return undefined;
+ if (fetchUrl instanceof URL) return fetchUrl.href;
+ return fetchUrl;
+ }
+
+ const fetcherUrl = (() => {
+ const urlAsString = fetchUrlToString(baseUrl);
+ if (!urlAsString) return url;
+ const normalizedUrl = fetchUrlToString(url).replace(/\//, '');
+ const normalizedBaseUrl = urlAsString.replace(/\/$/, '');
+
+ return `${normalizedBaseUrl}/${normalizedUrl}`;
+ })();
+
+ let response: Response | undefined;
+
+ response = await fetch(fetcherUrl, fetcherOptionsWithDefaults);
+
+ if (
+ !response.ok &&
+ response.status === 401 &&
+ fetcherOptions.authenticated
+ ) {
+ let refetchAccessTokenSuccess: SignInSuccessResponse | undefined;
+ try {
+ refetchAccessTokenSuccess = await apiClient(
+ apiPaths.worker.obtainAccessToken.path,
+ {
+ successSchema: signInSuccessResponseSchema,
+ options: {
+ method: 'POST',
+ body: JSON.stringify({
+ // eslint-disable-next-line camelcase -- camel case defined by api
+ refresh_token: browserAuthProvider.getRefreshToken(),
+ }),
+ },
+ }
+ );
+ browserAuthProvider.signIn(
+ refetchAccessTokenSuccess,
+ browserAuthProvider.authType
+ );
+ } catch {
+ browserAuthProvider.signOut(() => {
+ window.location.reload();
+ });
+ return;
+ }
+
+ const newHeaders = appendHeader(fetcherOptionsWithDefaults, {
+ Authorization: `Bearer ${refetchAccessTokenSuccess.access_token}`,
+ });
+ response = await fetch(fetcherUrl, newHeaders);
+
+ if (!response.ok) {
+ browserAuthProvider.signOut(() => {
+ window.location.reload();
+ });
+ return;
+ }
+ }
+
+ let data: unknown = null;
+ try {
+ data = await response.json();
+ } catch {
+ try {
+ data = await response.text();
+ } catch (error) {
+ data = null;
+ }
+ }
+
+ if (!response.ok) {
+ throw new FetchError({
+ status: response.status,
+ message: response.statusText,
+ data,
+ });
+ }
+
+ if (fetcherOptions.skipValidation) {
+ return data;
+ }
+
+ try {
+ return fetcherOptions.successSchema.parse(data);
+ } catch (error) {
+ if (error instanceof ZodError) {
+ // eslint-disable-next-line no-console -- ...
+ console.error('Invalid response');
+ error.errors.forEach((e) => {
+ // eslint-disable-next-line no-console -- ...
+ console.error(e);
+ });
+ }
+ throw error;
+ }
+ }
+
+ return fetcher;
+}
+
+export const isFetcherError = (error: ResponseError): error is FetchError =>
+ error instanceof FetchError;
diff --git a/packages/apps/human-app/frontend/src/api/servieces/common/get-access-token.ts b/packages/apps/human-app/frontend/src/api/servieces/common/get-access-token.ts
new file mode 100644
index 0000000000..88b274d05e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/common/get-access-token.ts
@@ -0,0 +1,50 @@
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { signInSuccessResponseSchema } from '@/api/servieces/worker/sign-in';
+import { useAuth } from '@/auth/use-auth';
+import { browserAuthProvider } from '@/shared/helpers/browser-auth-provider';
+import type { AuthType } from '@/shared/types/browser-auth-provider';
+import { useWeb3Auth } from '@/auth-web3/use-web3-auth';
+
+export function useGetAccessTokenMutation() {
+ const queryClient = useQueryClient();
+ const { signIn: signInWeb2 } = useAuth();
+ const { signIn: signInWeb3 } = useWeb3Auth();
+
+ return useMutation({
+ mutationFn: async (authType: AuthType) => {
+ try {
+ const refetchAccessTokenSuccess = await apiClient(
+ apiPaths.worker.obtainAccessToken.path,
+ {
+ successSchema: signInSuccessResponseSchema,
+ options: {
+ method: 'POST',
+ body: JSON.stringify({
+ // eslint-disable-next-line camelcase -- camel case defined by api
+ refresh_token: browserAuthProvider.getRefreshToken(),
+ }),
+ },
+ }
+ );
+
+ if (authType === 'web2') {
+ signInWeb2(refetchAccessTokenSuccess);
+ } else {
+ signInWeb3(refetchAccessTokenSuccess);
+ }
+ } catch (error) {
+ browserAuthProvider.signOut(() => {
+ window.location.reload();
+ });
+ }
+ },
+ onSuccess: async () => {
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/common/prepare-signature.ts b/packages/apps/human-app/frontend/src/api/servieces/common/prepare-signature.ts
new file mode 100644
index 0000000000..e17c73a50f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/common/prepare-signature.ts
@@ -0,0 +1,40 @@
+import { z } from 'zod';
+import { useQuery } from '@tanstack/react-query';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+
+export enum PrepareSignatureType {
+ SignUp = 'SIGNUP',
+ SignIn = 'SIGNIN',
+ DisableOperator = 'DISABLE_OPERATOR',
+ RegisterAddress = 'REGISTER_ADDRESS',
+}
+
+export const prepareSignatureSuccessSchema = z.object({
+ from: z.string(),
+ to: z.string(),
+ contents: z.string(),
+ nonce: z.unknown(),
+});
+
+export type SignatureData = z.infer;
+export interface PrepareSignatureBody {
+ address: string;
+ type: PrepareSignatureType;
+}
+
+export const prepareSignature = (body: PrepareSignatureBody) => {
+ return apiClient(apiPaths.operator.web3Auth.prepareSignature.path, {
+ successSchema: prepareSignatureSuccessSchema,
+ options: { method: 'POST', body: JSON.stringify(body) },
+ });
+};
+
+export function usePrepareSignature(body: PrepareSignatureBody) {
+ return useQuery({
+ queryFn: () => prepareSignature(body),
+ refetchInterval: 0,
+ // eslint-disable-next-line @tanstack/query/exhaustive-deps -- ...
+ queryKey: ['prepareSignature'],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/enums.ts b/packages/apps/human-app/frontend/src/api/servieces/enums.ts
new file mode 100644
index 0000000000..deb82a5fd4
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/enums.ts
@@ -0,0 +1,3 @@
+import { z } from 'zod';
+
+export const testType = z.enum(['TYPE']);
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/add-stake.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/add-stake.ts
new file mode 100644
index 0000000000..43a91a839c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/add-stake.ts
@@ -0,0 +1,138 @@
+import { z } from 'zod';
+import last from 'lodash/last';
+import type { MutationState } from '@tanstack/react-query';
+import {
+ useMutation,
+ useMutationState,
+ useQueryClient,
+} from '@tanstack/react-query';
+import { t } from 'i18next';
+import { useNavigate } from 'react-router-dom';
+import { ethers } from 'ethers';
+import { stakingStake } from '@/smart-contracts/Staking/staking-stake';
+import type { ResponseError } from '@/shared/types/global.type';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { getContractAddress } from '@/smart-contracts/get-contract-address';
+import { hmTokenApprove } from '@/smart-contracts/HMToken/hm-token-approve';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import { routerPaths } from '@/router/router-paths';
+import { hmTokenAllowance } from '@/smart-contracts/HMToken/hm-token-allowance';
+import { useHMTokenDecimals } from '@/api/servieces/operator/human-token-decimals';
+
+type AmountValidation = z.ZodEffects<
+ z.ZodEffects,
+ string,
+ string
+>;
+type AmountField = z.infer;
+
+export const addStakeAmountCallArgumentsSchema = (
+ decimals: number
+): AmountValidation =>
+ z
+ .string()
+ .refine((amount) => !amount.startsWith('-'))
+ .refine(
+ (amount) => {
+ const decimalPart = amount.toString().split('.')[1];
+ if (!decimalPart) return true;
+ return decimalPart.length <= decimals;
+ },
+ {
+ message: t('operator.stakeForm.invalidDecimals', {
+ decimals,
+ }),
+ }
+ );
+
+export interface AddStakeCallArguments {
+ amount: AmountField;
+}
+
+async function addStakeMutationFn(
+ data: AddStakeCallArguments & {
+ address: string;
+ amount: string;
+ decimals?: number;
+ } & Omit
+) {
+ const stakingContractAddress = getContractAddress({
+ contractName: 'Staking',
+ });
+
+ const hmTokenContractAddress = getContractAddress({
+ contractName: 'HMToken',
+ });
+
+ const allowance = await hmTokenAllowance({
+ spender: stakingContractAddress,
+ owner: data.address || '',
+ contractAddress: hmTokenContractAddress,
+ provider: data.provider,
+ signer: data.signer,
+ chainId: data.chainId,
+ });
+
+ const amountBigInt = ethers.parseUnits(data.amount, data.decimals);
+ if (amountBigInt - allowance > 0) {
+ await hmTokenApprove({
+ spender: stakingContractAddress,
+ contractAddress: hmTokenContractAddress,
+ amount: amountBigInt.toString(),
+ provider: data.provider,
+ signer: data.signer,
+ chainId: data.chainId,
+ });
+ }
+ await stakingStake({
+ ...data,
+ amount: amountBigInt.toString(),
+ contractAddress: stakingContractAddress,
+ });
+ return data;
+}
+
+export function useAddStakeMutation() {
+ const {
+ chainId,
+ address,
+ web3ProviderMutation: { data: web3data },
+ } = useConnectedWallet();
+ const { data: HMTDecimals } = useHMTokenDecimals();
+
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
+
+ return useMutation({
+ mutationFn: (data: AddStakeCallArguments) =>
+ addStakeMutationFn({
+ ...data,
+ address,
+ provider: web3data?.provider,
+ signer: web3data?.signer,
+ chainId,
+ decimals: HMTDecimals,
+ }),
+ onSuccess: async () => {
+ navigate(routerPaths.operator.addKeys);
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ mutationKey: ['addStake', address],
+ });
+}
+
+export function useAddStakeMutationState() {
+ const { address } = useConnectedWallet();
+
+ const state = useMutationState({
+ filters: { mutationKey: ['addStake', address] },
+ select: (mutation) => mutation.state,
+ });
+
+ return last(state) as
+ | MutationState
+ | undefined;
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/disable-operator.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/disable-operator.ts
new file mode 100644
index 0000000000..b7d1c84f76
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/disable-operator.ts
@@ -0,0 +1,29 @@
+import { useMutation } from '@tanstack/react-query';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { useGetAccessTokenMutation } from '@/api/servieces/common/get-access-token';
+import { useWeb3AuthenticatedUser } from '@/auth-web3/use-web3-authenticated-user';
+
+export function useDisableWeb3Operator() {
+ const { address, chainId } = useConnectedWallet();
+ const { mutateAsync } = useGetAccessTokenMutation();
+ const { updateUserData } = useWeb3AuthenticatedUser();
+ return useMutation({
+ mutationFn: async ({ signature }: { signature: string }) => {
+ const result = apiClient(apiPaths.operator.disableOperator.path, {
+ skipValidation: true,
+ authenticated: true,
+ options: {
+ method: 'POST',
+ body: JSON.stringify({ signature }),
+ },
+ });
+
+ await mutateAsync('web3');
+ updateUserData({ status: 'INACTIVE' });
+ return result;
+ },
+ mutationKey: ['disableOperator', address, chainId],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/edit-existing-keys.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/edit-existing-keys.ts
new file mode 100644
index 0000000000..54453a0f72
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/edit-existing-keys.ts
@@ -0,0 +1,147 @@
+import {
+ useMutation,
+ useMutationState,
+ useQueryClient,
+} from '@tanstack/react-query';
+import last from 'lodash/last';
+import { useNavigate } from 'react-router-dom';
+import type { JsonRpcSigner } from 'ethers';
+import { z } from 'zod';
+import { t } from 'i18next';
+import { routerPaths } from '@/router/router-paths';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import {
+ EthKVStoreKeys,
+ JobTypes,
+ Role,
+} from '@/smart-contracts/EthKVStore/config';
+import { ethKvStoreSetBulk } from '@/smart-contracts/EthKVStore/eth-kv-store-set-bulk';
+import { getContractAddress } from '@/smart-contracts/get-contract-address';
+import type { GetEthKVStoreValuesSuccessResponse } from '@/api/servieces/operator/get-keys';
+import { isArray } from '@/shared/helpers/is-array';
+
+export const editEthKVStoreValuesMutationSchema = z.object({
+ [EthKVStoreKeys.PublicKey]: z.string().min(1).optional(),
+ [EthKVStoreKeys.Url]: z.string().url().optional(),
+ [EthKVStoreKeys.WebhookUrl]: z.string().url().optional(),
+ [EthKVStoreKeys.Role]: z.nativeEnum(Role).optional(),
+ [EthKVStoreKeys.JobTypes]: z.array(z.nativeEnum(JobTypes)).optional(),
+ [EthKVStoreKeys.Fee]: z.coerce.number().min(1).max(100).step(1).optional(),
+});
+
+export type EditEthKVStoreValuesMutationData = z.infer<
+ typeof editEthKVStoreValuesMutationSchema
+>;
+
+export const getEditEthKVStoreValuesMutationSchema = (
+ initialData: GetEthKVStoreValuesSuccessResponse
+) => {
+ return editEthKVStoreValuesMutationSchema.transform((newData, ctx) => {
+ const result: EditEthKVStoreValuesMutationData = {};
+ Object.values(EthKVStoreKeys).forEach((key) => {
+ const newFiledData = newData[key];
+ const initialFiledData = initialData[key];
+
+ if (
+ isArray(newFiledData) &&
+ isArray(initialFiledData) &&
+ newFiledData.sort().toString() !== initialFiledData.sort().toString()
+ ) {
+ Object.assign(result, { [key]: newFiledData.toString() });
+ return;
+ }
+
+ if (
+ typeof newFiledData === 'number' &&
+ newFiledData.toString() !== initialFiledData?.toString()
+ ) {
+ Object.assign(result, { [key]: newFiledData });
+ return;
+ }
+
+ if (newFiledData !== initialFiledData) {
+ Object.assign(result, { [key]: newFiledData });
+ }
+ });
+
+ if (!Object.values(result).length) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: t('operator.addKeysPage.editKeysForm.error'),
+ path: ['form'],
+ });
+ }
+
+ return result;
+ });
+};
+
+function editExistingKeysMutationFn(
+ formData: EditEthKVStoreValuesMutationData,
+ userData: {
+ accountAddress: string;
+ chainId: number;
+ signer?: JsonRpcSigner;
+ }
+) {
+ const contractAddress = getContractAddress({
+ contractName: 'EthKVStore',
+ });
+
+ const keys: string[] = [];
+ const values: string[] = [];
+
+ Object.entries(formData).forEach(([formFieldName, formFieldValue]) => {
+ if (!formFieldValue) {
+ return;
+ }
+ keys.push(formFieldName);
+ values.push(formFieldValue.toString());
+ });
+
+ return ethKvStoreSetBulk({
+ keys,
+ values,
+ contractAddress,
+ chainId: userData.chainId,
+ signer: userData.signer,
+ });
+}
+
+export function useEditExistingKeysMutation() {
+ const {
+ address,
+ chainId,
+ web3ProviderMutation: { data: web3Data },
+ } = useConnectedWallet();
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
+
+ return useMutation({
+ mutationFn: (data: EditEthKVStoreValuesMutationData) =>
+ editExistingKeysMutationFn(data, {
+ accountAddress: address,
+ chainId,
+ signer: web3Data?.signer,
+ }),
+ onSuccess: async () => {
+ navigate(routerPaths.operator.editExistingKeysSuccess);
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ mutationKey: ['editKeys', address],
+ });
+}
+
+export function useEditExistingKeysMutationState() {
+ const { address } = useConnectedWallet();
+
+ const state = useMutationState({
+ filters: { mutationKey: ['editKeys', address] },
+ select: (mutation) => mutation.state,
+ });
+
+ return last(state);
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/get-keys.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/get-keys.ts
new file mode 100644
index 0000000000..27701b4090
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/get-keys.ts
@@ -0,0 +1,51 @@
+import { useQuery } from '@tanstack/react-query';
+import { z } from 'zod';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { ethKVStoreGetKeys } from '@/smart-contracts/EthKVStore/eth-kv-store-get-keys';
+import { getContractAddress } from '@/smart-contracts/get-contract-address';
+import { EthKVStoreKeys } from '@/smart-contracts/EthKVStore/config';
+
+export const getEthKVStoreValuesSuccessSchema = z.object({
+ [EthKVStoreKeys.PublicKey]: z.string().optional(),
+ [EthKVStoreKeys.Url]: z.string().optional(),
+ [EthKVStoreKeys.WebhookUrl]: z.string().optional(),
+ [EthKVStoreKeys.Role]: z.string().optional(),
+ [EthKVStoreKeys.Fee]: z.string().optional(),
+ [EthKVStoreKeys.JobTypes]: z
+ .string()
+ .transform((jobTypes) => {
+ if (!jobTypes) return undefined;
+ return jobTypes.split(',');
+ })
+ .optional(),
+});
+
+export type GetEthKVStoreValuesSuccessResponse = z.infer<
+ typeof getEthKVStoreValuesSuccessSchema
+>;
+
+export function useGetKeys() {
+ const {
+ chainId,
+ address,
+ web3ProviderMutation: { data },
+ } = useConnectedWallet();
+
+ return useQuery({
+ queryFn: async () => {
+ const contractAddress = getContractAddress({
+ contractName: 'EthKVStore',
+ });
+ const result = await ethKVStoreGetKeys({
+ accountAddress: address,
+ contractAddress,
+ chainId,
+ signer: data?.signer,
+ });
+
+ const validData = getEthKVStoreValuesSuccessSchema.parse(result);
+ return validData;
+ },
+ queryKey: [chainId, address, data?.signer],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/get-stacked-amount.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/get-stacked-amount.ts
new file mode 100644
index 0000000000..dd1c58ee34
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/get-stacked-amount.ts
@@ -0,0 +1,42 @@
+import { useQuery } from '@tanstack/react-query';
+import { ethers } from 'ethers';
+import { t } from 'i18next';
+import { stakingGetStakedTokens } from '@/smart-contracts/Staking/staking-get-staked-tokens';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { getContractAddress } from '@/smart-contracts/get-contract-address';
+
+export const stakedAmountFormatter = (amount: bigint) => {
+ const amountAsString = ethers.formatEther(amount);
+
+ if (amountAsString.split('.')[1] === '0') {
+ // decimals part should be omitted
+ return `${amountAsString.replace('.0', '')} ${t('inputMasks.humanCurrencySuffix')}`;
+ }
+ return `${ethers.formatEther(amount)} ${t('inputMasks.humanCurrencySuffix')}`;
+};
+
+export function useGetStakedAmount() {
+ const {
+ address,
+ chainId,
+ web3ProviderMutation: { data },
+ } = useConnectedWallet();
+
+ return useQuery({
+ queryFn: async () => {
+ const contractAddress = getContractAddress({
+ contractName: 'Staking',
+ });
+ const stakeAmount = await stakingGetStakedTokens({
+ contractAddress,
+ stakerAddress: address,
+ chainId,
+ signer: data?.signer,
+ });
+
+ return stakeAmount;
+ },
+ queryKey: ['getStackedAmount', address, chainId, data?.signer],
+ refetchInterval: 0,
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/get-stats.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/get-stats.ts
new file mode 100644
index 0000000000..31bd315688
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/get-stats.ts
@@ -0,0 +1,44 @@
+/* eslint-disable camelcase -- ... */
+import { useQuery } from '@tanstack/react-query';
+import { z } from 'zod';
+import { apiClient } from '@/api/api-client';
+import { useGetKeys } from '@/api/servieces/operator/get-keys';
+
+const operatorStatsSuccessResponseSchema = z.object({
+ workers_total: z.number(),
+ assignments_completed: z.number(),
+ assignments_expired: z.number(),
+ assignments_rejected: z.number(),
+});
+
+export type OperatorStatsSuccessResponse = z.infer<
+ typeof operatorStatsSuccessResponseSchema
+>;
+
+const failedResponse = {
+ workers_total: '-',
+ assignments_completed: '-',
+ assignments_expired: '-',
+ assignments_rejected: '-',
+};
+
+export function useGetOperatorStats() {
+ const { data: keysData } = useGetKeys();
+
+ return useQuery({
+ queryFn: async () => {
+ if (!keysData?.url) {
+ return failedResponse;
+ }
+ return apiClient(`/stats`, {
+ baseUrl: keysData.url,
+ successSchema: operatorStatsSuccessResponseSchema,
+ options: {
+ method: 'GET',
+ },
+ }).catch(() => failedResponse);
+ },
+ // eslint-disable-next-line @tanstack/query/exhaustive-deps -- ...
+ queryKey: ['getOperatorStats', keysData?.url],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/human-token-decimals.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/human-token-decimals.ts
new file mode 100644
index 0000000000..a9cd80d57b
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/human-token-decimals.ts
@@ -0,0 +1,25 @@
+import { useQuery } from '@tanstack/react-query';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { hmTokenDecimals } from '@/smart-contracts/HMToken/hm-token-decimals';
+import { getContractAddress } from '@/smart-contracts/get-contract-address';
+
+export function useHMTokenDecimals() {
+ const {
+ chainId,
+ web3ProviderMutation: { data },
+ } = useConnectedWallet();
+
+ return useQuery({
+ queryFn: () => {
+ const contractAddress = getContractAddress({
+ contractName: 'HMToken',
+ });
+ return hmTokenDecimals({
+ contractAddress,
+ chainId,
+ signer: data?.signer,
+ });
+ },
+ queryKey: ['decimals', chainId, data?.signer || 'signer'],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/web3-signin.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/web3-signin.ts
new file mode 100644
index 0000000000..f3eea2535e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/web3-signin.ts
@@ -0,0 +1,49 @@
+/* eslint-disable camelcase -- ...*/
+import { useMutation } from '@tanstack/react-query';
+import { z } from 'zod';
+import { useNavigate } from 'react-router-dom';
+import { t } from 'i18next';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { useWeb3Auth } from '@/auth-web3/use-web3-auth';
+import { routerPaths } from '@/router/router-paths';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+import type { PrepareSignatureBody } from '@/api/servieces/common/prepare-signature';
+import { prepareSignature } from '@/api/servieces/common/prepare-signature';
+
+export const web3SignInSuccessResponseSchema = z.object({
+ access_token: z.string(),
+ refresh_token: z.string(),
+});
+
+export type Web3SignInSuccessResponse = z.infer<
+ typeof web3SignInSuccessResponseSchema
+>;
+
+export function useWeb3SignIn() {
+ const { address, chainId, signMessage } = useWalletConnect();
+ const { signIn } = useWeb3Auth();
+ const navigate = useNavigate();
+ return useMutation({
+ mutationFn: async (body: PrepareSignatureBody) => {
+ const dataToSign = await prepareSignature(body);
+ if (!signMessage) {
+ throw new Error(t('errors.unknown'));
+ }
+ const signature = await signMessage(JSON.stringify(dataToSign));
+
+ return apiClient(apiPaths.operator.web3Auth.signIn.path, {
+ successSchema: web3SignInSuccessResponseSchema,
+ options: {
+ method: 'POST',
+ body: JSON.stringify({ address, signature }),
+ },
+ });
+ },
+ onSuccess: (successResponse) => {
+ signIn(successResponse);
+ navigate(routerPaths.operator.profile);
+ },
+ mutationKey: ['web3SignIn', address, chainId],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/operator/web3-signup.ts b/packages/apps/human-app/frontend/src/api/servieces/operator/web3-signup.ts
new file mode 100644
index 0000000000..acb068915f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/operator/web3-signup.ts
@@ -0,0 +1,39 @@
+/* eslint-disable camelcase -- ...*/
+import { useMutation } from '@tanstack/react-query';
+import { z } from 'zod';
+import { useNavigate } from 'react-router-dom';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { useWeb3Auth } from '@/auth-web3/use-web3-auth';
+import { routerPaths } from '@/router/router-paths';
+
+export const web3SignInSuccessResponseSchema = z.object({
+ access_token: z.string(),
+ refresh_token: z.string(),
+});
+
+export type Web3SignInSuccessResponse = z.infer<
+ typeof web3SignInSuccessResponseSchema
+>;
+
+export function useWeb3SignUp() {
+ const { address, chainId } = useConnectedWallet();
+ const { signIn } = useWeb3Auth();
+ const navigate = useNavigate();
+ return useMutation({
+ mutationFn: async ({ signature }: { signature: string }) =>
+ apiClient(apiPaths.operator.web3Auth.signUp.path, {
+ successSchema: web3SignInSuccessResponseSchema,
+ options: {
+ method: 'POST',
+ body: JSON.stringify({ address, signature }),
+ },
+ }),
+ onSuccess: (successResponse) => {
+ signIn(successResponse);
+ navigate(routerPaths.operator.profile);
+ },
+ mutationKey: ['web3SignUp', address, chainId],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/test.schema.ts b/packages/apps/human-app/frontend/src/api/servieces/test.schema.ts
new file mode 100644
index 0000000000..04c6b07050
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/test.schema.ts
@@ -0,0 +1,7 @@
+import { z } from 'zod';
+import { testDataSchema } from '@/shared/types/entity.type';
+
+export const testSchema = z.object({
+ requestId: z.string(),
+ timestamp: testDataSchema,
+});
diff --git a/packages/apps/human-app/frontend/src/api/servieces/test.service.ts b/packages/apps/human-app/frontend/src/api/servieces/test.service.ts
new file mode 100644
index 0000000000..d2d6facd50
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/test.service.ts
@@ -0,0 +1,19 @@
+import { useQuery } from '@tanstack/react-query';
+import { apiClient } from '../api-client';
+import { apiPaths } from '../api-paths';
+import { testSchema } from './test.schema';
+
+function getTest() {
+ return apiClient(apiPaths.test.path, {
+ options: { method: 'GET' },
+ successSchema: testSchema,
+ });
+}
+
+export function useGetTest() {
+ return useQuery({
+ queryKey: ['test'],
+ retry: false,
+ queryFn: getTest,
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/assign-job.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/assign-job.ts
new file mode 100644
index 0000000000..339b54cf92
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/assign-job.ts
@@ -0,0 +1,38 @@
+import { z } from 'zod';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+
+export interface AssignJobBody {
+ escrow_address: string;
+ chain_id: number;
+}
+
+const AssignJobBodySuccessResponseSchema = z.unknown();
+
+function assignJob(data: AssignJobBody) {
+ return apiClient(apiPaths.worker.assignJob.path, {
+ authenticated: true,
+ successSchema: AssignJobBodySuccessResponseSchema,
+ options: { method: 'POST', body: JSON.stringify(data) },
+ });
+}
+
+export function useAssignJobMutation(callbacks?: {
+ onSuccess: () => Promise;
+ onError: (error: unknown) => Promise;
+}) {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: assignJob,
+ onSuccess: async () => {
+ await queryClient.invalidateQueries();
+ await callbacks?.onSuccess();
+ },
+ onError: async (error) => {
+ await queryClient.invalidateQueries();
+ await callbacks?.onError(error);
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/available-jobs-data.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/available-jobs-data.ts
new file mode 100644
index 0000000000..8c7e465f0f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/available-jobs-data.ts
@@ -0,0 +1,73 @@
+/* eslint-disable camelcase -- api response*/
+import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
+import { z } from 'zod';
+import { useParams } from 'react-router-dom';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { stringifyUrlQueryObject } from '@/shared/helpers/stringify-url-query-object';
+import type { JobsFilterStoreProps } from '@/hooks/use-jobs-filter-store';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import { createPaginationSchema } from '@/shared/helpers/create-pagination-schema';
+
+const availableJobSchema = z.object({
+ escrow_address: z.string(),
+ chain_id: z.number(),
+ job_type: z.string(),
+ status: z.string(),
+ job_description: z.string().optional(),
+ reward_amount: z.number().optional(),
+ reward_token: z.string().optional(),
+});
+
+const availableJobsSuccessResponseSchema =
+ createPaginationSchema(availableJobSchema);
+
+export type AvailableJob = z.infer;
+export type AvailableJobsSuccessResponse = z.infer<
+ typeof availableJobsSuccessResponseSchema
+>;
+
+type GetJobTableDataDto = JobsFilterStoreProps['filterParams'] & {
+ oracle_address: string;
+};
+
+const getAvailableJobsTableData = async (dto: GetJobTableDataDto) => {
+ return apiClient(
+ `${apiPaths.worker.jobs.path}?${stringifyUrlQueryObject({ ...dto })}`,
+ {
+ authenticated: true,
+ successSchema: availableJobsSuccessResponseSchema,
+ options: {
+ method: 'GET',
+ },
+ }
+ );
+};
+
+export function useGetAvailableJobsData() {
+ const { filterParams } = useJobsFilterStore();
+ const { address: oracle_address } = useParams<{ address: string }>();
+ const dto = { ...filterParams, oracle_address: oracle_address || '' };
+
+ return useQuery({
+ queryKey: ['availableJobs', dto],
+ queryFn: () => getAvailableJobsTableData(dto),
+ });
+}
+
+export function useInfiniteGetAvailableJobsData() {
+ const { filterParams } = useJobsFilterStore();
+ const { address: oracle_address } = useParams<{ address: string }>();
+ const dto = { ...filterParams, oracle_address: oracle_address || '' };
+
+ return useInfiniteQuery({
+ initialPageParam: 0,
+ queryKey: ['availableJobsInfinite', dto],
+ queryFn: () => getAvailableJobsTableData(dto),
+ getNextPageParam: (pageParams) => {
+ return pageParams.total_pages - 1 <= pageParams.page
+ ? undefined
+ : pageParams.page;
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/available-jobs-table-service-mock.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/available-jobs-table-service-mock.ts
new file mode 100644
index 0000000000..12f3f58ce6
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/available-jobs-table-service-mock.ts
@@ -0,0 +1,58 @@
+/* eslint-disable camelcase -- output from api */
+export interface AvailableJobs {
+ page: number;
+ page_size: number;
+ total_pages: number;
+ total_results: number;
+ results: JobsArray[];
+}
+
+export interface JobsArray {
+ escrow_address: string;
+ chain_id: number;
+ job_type: string;
+ status: string;
+}
+
+const data: AvailableJobs = {
+ page: 0,
+ page_size: 5,
+ total_pages: 2,
+ total_results: 7,
+ results: [
+ {
+ escrow_address: '0x2db00C8A1793424e35f6Cc634Eb13CC174929A4A',
+ chain_id: 80002,
+ job_type: 'FORTUNE',
+ status: 'ACTIVE',
+ },
+ {
+ escrow_address: '0x7Cf6978f8699Cf22a121B6332BDF3c5C2F10e3e3',
+ chain_id: 80002,
+ job_type: 'FORTUNE',
+ status: 'ACTIVE',
+ },
+ {
+ escrow_address: '0xb389ac3678bF3723863dF92B5D531b0d12e82431',
+ chain_id: 80002,
+ job_type: 'FORTUNE',
+ status: 'ACTIVE',
+ },
+ {
+ escrow_address: '0xe9B9b198b093A078Fe8900b703637C26FD2f06a4',
+ chain_id: 80002,
+ job_type: 'FORTUNE',
+ status: 'ACTIVE',
+ },
+ {
+ escrow_address: '0x531e2CDB13f2c5606F8C251799f93CBb1219C14C',
+ chain_id: 80002,
+ job_type: 'FORTUNE',
+ status: 'ACTIVE',
+ },
+ ],
+};
+
+export function getJobsTableData(): Promise {
+ return Promise.resolve(data);
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/daily-hmt-spent.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/daily-hmt-spent.ts
new file mode 100644
index 0000000000..d259f47ee6
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/daily-hmt-spent.ts
@@ -0,0 +1,25 @@
+import { z } from 'zod';
+import { useQuery } from '@tanstack/react-query';
+import { apiPaths } from '@/api/api-paths';
+import { apiClient } from '@/api/api-client';
+
+const dailyHmtSpentSchema = z.object({
+ spend: z.number(),
+});
+
+export type DailyHmtSpentSchemaSuccess = z.infer;
+
+export async function getDailyHmtSpent() {
+ return apiClient(apiPaths.worker.dailyHmtSpend, {
+ successSchema: dailyHmtSpentSchema,
+ authenticated: true,
+ options: { method: 'GET' },
+ });
+}
+
+export function useDailyHmtSpent() {
+ return useQuery({
+ queryFn: getDailyHmtSpent,
+ queryKey: ['getDailyHmtSpent'],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/email-verification.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/email-verification.ts
new file mode 100644
index 0000000000..ea9dcb6d9d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/email-verification.ts
@@ -0,0 +1,28 @@
+import { z } from 'zod';
+import { useQuery } from '@tanstack/react-query';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+
+export const verifyEmailDtoSchema = z.object({
+ token: z.string(),
+});
+
+export type VerifyDto = z.infer;
+
+const VerifyEmailSuccessResponseSchema = z.unknown();
+
+async function verifyEmailQueryFn(data: VerifyDto) {
+ return apiClient(apiPaths.worker.verifyEmail.path, {
+ authenticated: true,
+ successSchema: VerifyEmailSuccessResponseSchema,
+ options: { method: 'POST', body: JSON.stringify(data) },
+ });
+}
+
+export function useVerifyEmailQuery({ token }: { token: string }) {
+ return useQuery({
+ queryFn: () => verifyEmailQueryFn({ token }),
+ queryKey: [token],
+ refetchInterval: 0,
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/enable-hcaptcha-labeling.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/enable-hcaptcha-labeling.ts
new file mode 100644
index 0000000000..74fc44a8bf
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/enable-hcaptcha-labeling.ts
@@ -0,0 +1,41 @@
+/* eslint-disable camelcase -- ...*/
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useNavigate } from 'react-router-dom';
+import { z } from 'zod';
+import { routerPaths } from '@/router/router-paths';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { useGetAccessTokenMutation } from '@/api/servieces/common/get-access-token';
+
+const enableHCaptchaLabelingSuccessSchema = z.object({
+ site_key: z.string(),
+});
+
+export type EnableHCaptchaLabelingSuccessResponse = z.infer<
+ typeof enableHCaptchaLabelingSuccessSchema
+>;
+
+export function useEnableHCaptchaLabelingMutation() {
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
+ const { mutateAsync: getAccessTokenMutation } = useGetAccessTokenMutation();
+
+ return useMutation({
+ mutationFn: async () => {
+ const result = await apiClient(apiPaths.worker.enableHCaptchaLabeling, {
+ successSchema: enableHCaptchaLabelingSuccessSchema,
+ authenticated: true,
+ options: { method: 'POST' },
+ });
+ await getAccessTokenMutation('web2');
+ return result;
+ },
+ onSuccess: async () => {
+ navigate(routerPaths.worker.HcaptchaLabeling);
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/get-kyc-session-id.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/get-kyc-session-id.ts
new file mode 100644
index 0000000000..102d14d44e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/get-kyc-session-id.ts
@@ -0,0 +1,44 @@
+/* eslint-disable camelcase -- ...*/
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { z } from 'zod';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { useGetAccessTokenMutation } from '@/api/servieces/common/get-access-token';
+
+const kycSessionIdSchema = z.object({
+ session_id: z.string(),
+});
+
+export type KycSessionIdSuccessSchema = z.infer;
+
+export function useKycSessionIdMutation() {
+ const queryClient = useQueryClient();
+ const { user } = useAuthenticatedUser();
+ const { mutateAsync: getAccessTokenMutation } = useGetAccessTokenMutation();
+ return useMutation({
+ mutationFn: async () => {
+ try {
+ const result = await apiClient(apiPaths.worker.kycSessionId.path, {
+ successSchema: kycSessionIdSchema,
+ authenticated: true,
+ options: {
+ method: 'POST',
+ },
+ });
+ return result;
+ } catch (error) {
+ await getAccessTokenMutation('web2');
+ throw error;
+ }
+ },
+
+ onError: () => {
+ void queryClient.invalidateQueries();
+ },
+ onSuccess: () => {
+ void queryClient.invalidateQueries();
+ },
+ mutationKey: ['kycSessionId', user.email],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/get-on-chain-registered-address.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/get-on-chain-registered-address.ts
new file mode 100644
index 0000000000..f86ab857df
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/get-on-chain-registered-address.ts
@@ -0,0 +1,46 @@
+/* eslint-disable camelcase -- ... */
+import { z } from 'zod';
+import { useQuery } from '@tanstack/react-query';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { ethKVStoreGetKycData } from '@/smart-contracts/EthKVStore/eth-kv-store-get-kyc-data';
+import { getContractAddress } from '@/smart-contracts/get-contract-address';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+
+export interface RegisterAddressPayload {
+ address: string;
+}
+
+export const RegisterAddressSuccessSchema = z.object({
+ signed_address: z.string(),
+});
+
+export type RegisterAddressSuccess = z.infer<
+ typeof RegisterAddressSuccessSchema
+>;
+
+export function useGetOnChainRegisteredAddress() {
+ const { user } = useAuthenticatedUser();
+ const { address } = useWalletConnect();
+
+ return useQuery({
+ queryFn: async () => {
+ const contractAddress = getContractAddress({
+ contractName: 'EthKVStore',
+ });
+
+ const registeredAddressOnChain = await ethKVStoreGetKycData({
+ contractAddress,
+ accountAddress: user.wallet_address || address || '',
+ kycKey: `KYC-${user.reputation_network}`,
+ });
+
+ return registeredAddressOnChain;
+ },
+ retry: 0,
+ refetchInterval: 0,
+ refetchOnMount: false,
+ refetchOnWindowFocus: false,
+ refetchOnReconnect: false,
+ queryKey: [user.wallet_address, user.reputation_network, address],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/get-signed-address.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/get-signed-address.ts
new file mode 100644
index 0000000000..14965532d7
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/get-signed-address.ts
@@ -0,0 +1,28 @@
+import { useQuery } from '@tanstack/react-query';
+import { z } from 'zod';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+
+const signedAddressSuccessSchema = z.object({
+ key: z.string(),
+ value: z.string(),
+});
+
+export type SignedAddressSuccess = z.infer;
+
+const getSignedAddress = async () => {
+ return apiClient(apiPaths.worker.signedAddress.path, {
+ authenticated: true,
+ successSchema: signedAddressSuccessSchema,
+ options: {
+ method: 'GET',
+ },
+ });
+};
+
+export function useGetSignedAddress() {
+ return useQuery({
+ queryKey: ['getSignedAddress'],
+ queryFn: getSignedAddress,
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/hcaptcha-user-stats.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/hcaptcha-user-stats.ts
new file mode 100644
index 0000000000..425e74cefb
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/hcaptcha-user-stats.ts
@@ -0,0 +1,39 @@
+import { z } from 'zod';
+import { useQuery } from '@tanstack/react-query';
+import { apiPaths } from '@/api/api-paths';
+import { apiClient } from '@/api/api-client';
+
+const hcaptchaUserStatsSchema = z.object({
+ balance: z.object({
+ available: z.number(),
+ estimated: z.number(),
+ recent: z.number(),
+ total: z.number(),
+ }),
+ served: z.number(),
+ solved: z.number(),
+ verified: z.number(),
+ // TODO verify response
+ currentDateStats: z.unknown(),
+ // TODO verify response
+ currentEarningsStats: z.object({
+ hmtEarned: z.unknown(),
+ }),
+});
+
+export type HCaptchaUserStatsSuccess = z.infer;
+
+export async function getHCaptchaUsersStats() {
+ return apiClient(apiPaths.worker.hCaptchaUserStats, {
+ authenticated: true,
+ successSchema: hcaptchaUserStatsSchema,
+ options: { method: 'GET' },
+ });
+}
+
+export function useHCaptchaUserStats() {
+ return useQuery({
+ queryFn: getHCaptchaUsersStats,
+ queryKey: ['getHCaptchaUsersStats'],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/my-jobs-data.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/my-jobs-data.ts
new file mode 100644
index 0000000000..6f15bfadc7
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/my-jobs-data.ts
@@ -0,0 +1,88 @@
+/* eslint-disable camelcase -- api response*/
+import { useInfiniteQuery, useQuery } from '@tanstack/react-query';
+import { z } from 'zod';
+import { useParams } from 'react-router-dom';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { stringifyUrlQueryObject } from '@/shared/helpers/stringify-url-query-object';
+import { createPaginationSchema } from '@/shared/helpers/create-pagination-schema';
+import type { MyJobsFilterStoreProps } from '@/hooks/use-my-jobs-filter-store';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+
+const myJobSchema = z.object({
+ assignment_id: z.string(),
+ escrow_address: z.string(),
+ chain_id: z.number(),
+ job_type: z.string(),
+ status: z.string(),
+ reward_amount: z.string().transform((value, ctx) => {
+ const parsedNumber = Number(value);
+ if (Number.isNaN(parsedNumber)) {
+ ctx.addIssue({
+ path: ['results', 'reward_amount'],
+ message: 'Not a numeric string',
+ code: 'custom',
+ });
+ }
+
+ return parsedNumber;
+ }),
+ reward_token: z.string(),
+ created_at: z.string(),
+ expires_at: z.string(),
+ url: z.string().optional(),
+});
+
+const myJobsSuccessResponseSchema = createPaginationSchema(myJobSchema);
+
+export type MyJob = z.infer;
+export type MyJobsSuccessResponse = z.infer;
+export interface MyJobsWithJobTypes {
+ jobTypes: string[];
+ jobs: MyJobsSuccessResponse;
+}
+
+type GetMyJobTableDataDto = MyJobsFilterStoreProps['filterParams'] & {
+ oracle_address: string;
+};
+
+const getMyJobsTableData = async (dto: GetMyJobTableDataDto) => {
+ return apiClient(
+ `${apiPaths.worker.myJobs.path}?${stringifyUrlQueryObject({ ...dto })}`,
+ {
+ authenticated: true,
+ successSchema: myJobsSuccessResponseSchema,
+ options: {
+ method: 'GET',
+ },
+ }
+ );
+};
+
+export function useGetMyJobsData() {
+ const { filterParams } = useMyJobsFilterStore();
+ const { address } = useParams<{ address: string }>();
+ const dto = { ...filterParams, oracle_address: address || '' };
+
+ return useQuery({
+ queryKey: ['myJobs', dto],
+ queryFn: () => getMyJobsTableData(dto),
+ });
+}
+
+export function useInfiniteGetMyJobsData() {
+ const { filterParams } = useMyJobsFilterStore();
+ const { address } = useParams<{ address: string }>();
+ const dto = { ...filterParams, oracle_address: address || '' };
+
+ return useInfiniteQuery({
+ initialPageParam: 0,
+ queryKey: ['myJobsInfinite', dto],
+ queryFn: () => getMyJobsTableData(dto),
+ getNextPageParam: (pageParams) => {
+ return pageParams.total_pages - 1 <= pageParams.page
+ ? undefined
+ : pageParams.page;
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/my-jobs-table-service-mock.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/my-jobs-table-service-mock.ts
new file mode 100644
index 0000000000..3fd94cb3da
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/my-jobs-table-service-mock.ts
@@ -0,0 +1,58 @@
+/* eslint-disable camelcase -- output from api */
+export interface MyJobs {
+ page: number;
+ page_size: number;
+ total_pages: number;
+ total_results: number;
+ results: JobsArray[];
+}
+
+interface JobsArray {
+ assignment_id: number;
+ escrow_address: string;
+ chain_id: number;
+ job_type: string;
+ status: string;
+ reward_amount: number;
+ reward_token: string;
+ created_at: string;
+ expires_at: string;
+ url: string;
+}
+
+const data: MyJobs = {
+ page: 0,
+ page_size: 5,
+ total_pages: 1,
+ total_results: 2,
+ results: [
+ {
+ assignment_id: 8,
+ escrow_address: '0x2db00C8A1793424e35f6Cc634Eb13CC174929A4A',
+ chain_id: 80002,
+ job_type: 'FORTUNE',
+ status: 'ACTIVE',
+ reward_amount: 14.004735281093245,
+ reward_token: 'HMT',
+ created_at: '2024-04-22T14:38:03.956Z',
+ expires_at: '2024-07-25T06:05:16.000Z',
+ url: 'http://stg-fortune-exchange-oracle-server.humanprotocol.org',
+ },
+ {
+ assignment_id: 9,
+ escrow_address: '0xb389ac3678bF3723863dF92B5D531b0d12e82431',
+ chain_id: 80002,
+ job_type: 'FORTUNE',
+ status: 'ACTIVE',
+ reward_amount: 14.550093644402695,
+ reward_token: 'HMT',
+ created_at: '2024-04-23T08:24:14.274Z',
+ expires_at: '2024-07-27T14:25:15.000Z',
+ url: 'http://stg-fortune-exchange-oracle-server.humanprotocol.org',
+ },
+ ],
+};
+
+export function getJobsTableData(): Promise {
+ return Promise.resolve(data);
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/oracles.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/oracles.ts
new file mode 100644
index 0000000000..6fdbb8d80a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/oracles.ts
@@ -0,0 +1,42 @@
+/* eslint-disable camelcase -- ..*/
+import { z } from 'zod';
+import { useQuery } from '@tanstack/react-query';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { useJobsTypesOraclesFilter } from '@/hooks/use-job-types-oracles-table';
+import { stringifyUrlQueryObject } from '@/shared/helpers/stringify-url-query-object';
+
+const OracleSuccessSchema = z.object({
+ address: z.string(),
+ role: z.string(),
+ url: z.string().optional().nullable(),
+ jobTypes: z.array(z.string()),
+});
+
+const OraclesSuccessSchema = z.array(OracleSuccessSchema);
+
+export type OracleSuccessResponse = z.infer;
+export type OraclesSuccessResponse = OracleSuccessResponse[];
+
+export async function getOracles({
+ selected_job_types,
+}: {
+ selected_job_types: string[];
+}) {
+ const queryParams = selected_job_types.length
+ ? `?${stringifyUrlQueryObject({ selected_job_types })}`
+ : '';
+
+ return apiClient(`${apiPaths.worker.oracles.path}${queryParams}`, {
+ successSchema: OraclesSuccessSchema,
+ options: { method: 'GET' },
+ });
+}
+
+export function useGetOracles() {
+ const { selected_job_types } = useJobsTypesOraclesFilter();
+ return useQuery({
+ queryFn: () => getOracles({ selected_job_types }),
+ queryKey: ['oracles', selected_job_types],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/reject-task.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/reject-task.ts
new file mode 100644
index 0000000000..bf5e39679f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/reject-task.ts
@@ -0,0 +1,35 @@
+import { z } from 'zod';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+
+function rejectTask(data: { assignment_id: string; oracle_address: string }) {
+ return apiClient(apiPaths.worker.resignJob.path, {
+ successSchema: z.unknown(),
+ authenticated: true,
+ options: { method: 'POST', body: JSON.stringify(data) },
+ });
+}
+
+export function useRejectTaskMutation(callbacks?: {
+ onSuccess?: () => Promise;
+ onError?: (error: unknown) => Promise;
+}) {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: rejectTask,
+ onSuccess: async () => {
+ if (callbacks?.onSuccess) {
+ void callbacks.onSuccess();
+ }
+ await queryClient.invalidateQueries();
+ },
+ onError: async (error) => {
+ if (callbacks?.onError) {
+ void callbacks.onError(error);
+ }
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/resend-email-verification.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/resend-email-verification.ts
new file mode 100644
index 0000000000..93452b7c60
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/resend-email-verification.ts
@@ -0,0 +1,79 @@
+/* eslint-disable camelcase -- ...*/
+import { z } from 'zod';
+import type { MutationState } from '@tanstack/react-query';
+import {
+ useMutation,
+ useMutationState,
+ useQueryClient,
+} from '@tanstack/react-query';
+import last from 'lodash/last';
+import { t } from 'i18next';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import type { ResponseError } from '@/shared/types/global.type';
+import { useAuth } from '@/auth/use-auth';
+
+export const resendEmailVerificationHcaptchaSchema = z.object({
+ h_captcha_token: z.string(),
+});
+
+export type ResendEmailVerificationHcaptchaDto = z.infer<
+ typeof resendEmailVerificationHcaptchaSchema
+>;
+export const resendEmailVerificationEmailSchema = z.object({
+ email: z.string().email(),
+});
+
+export type ResendEmailVerificationEmailDto = z.infer<
+ typeof resendEmailVerificationEmailSchema
+>;
+
+export type ResendEmailVerificationDto = ResendEmailVerificationHcaptchaDto &
+ ResendEmailVerificationEmailDto;
+
+const ResendEmailVerificationSuccessResponseSchema = z.unknown();
+
+async function resendEmailVerificationMutationFn(
+ data: ResendEmailVerificationDto,
+ isAuthenticated: boolean
+) {
+ if (!isAuthenticated) {
+ throw new Error(t('worker.verifyEmail.authError'));
+ }
+
+ return apiClient(apiPaths.worker.resendEmailVerification.path, {
+ authenticated: true,
+ successSchema: ResendEmailVerificationSuccessResponseSchema,
+ options: { method: 'POST', body: JSON.stringify(data) },
+ });
+}
+
+const resendEmailVerificationKey = 'resendEmailVerification';
+
+export function useResendEmailVerificationWorkerMutation() {
+ const queryClient = useQueryClient();
+ const { user } = useAuth();
+
+ return useMutation({
+ mutationFn: (dto: ResendEmailVerificationDto) =>
+ resendEmailVerificationMutationFn(dto, Boolean(user)),
+ onSuccess: async () => {
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ mutationKey: [resendEmailVerificationKey],
+ });
+}
+
+export function useResendEmailVerificationWorkerMutationState() {
+ const state = useMutationState({
+ filters: { mutationKey: [resendEmailVerificationKey] },
+ select: (mutation) => mutation.state,
+ });
+
+ return last(state) as
+ | MutationState
+ | undefined;
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/reset-password.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/reset-password.ts
new file mode 100644
index 0000000000..c09e71ca08
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/reset-password.ts
@@ -0,0 +1,58 @@
+/* eslint-disable camelcase -- ... */
+import { z } from 'zod';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useNavigate } from 'react-router-dom';
+import { t } from 'i18next';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { passwordRegex } from '@/shared/helpers/regex';
+import { routerPaths } from '@/router/router-paths';
+
+export const resetPasswordDtoSchema = z
+ .object({
+ password: z
+ .string()
+ .max(50, t('validation.max', { count: 50 }))
+ .regex(passwordRegex, t('validation.passwordWeak')),
+ confirmPassword: z
+ .string()
+ .min(1, t('validation.required'))
+ .max(50, t('validation.max', { count: 50 })),
+ h_captcha_token: z
+ .string()
+ .min(1, t('validation.captcha'))
+ .default('token'),
+ })
+ .refine(({ password, confirmPassword }) => confirmPassword === password, {
+ message: t('validation.passwordMismatch'),
+ path: ['confirmPassword'],
+ });
+
+export type ResetPasswordDto = z.infer;
+
+const ResetPasswordSuccessResponseSchema = z.unknown();
+
+function resetPasswordMutationFn(
+ data: Omit & { token: string }
+) {
+ return apiClient(apiPaths.worker.resetPassword.path, {
+ successSchema: ResetPasswordSuccessResponseSchema,
+ options: { method: 'POST', body: JSON.stringify(data) },
+ });
+}
+
+export function useResetPasswordMutation() {
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
+
+ return useMutation({
+ mutationFn: resetPasswordMutationFn,
+ onSuccess: async () => {
+ navigate(routerPaths.worker.resetPasswordSuccess);
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/send-reset-link.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/send-reset-link.ts
new file mode 100644
index 0000000000..44aafb652c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/send-reset-link.ts
@@ -0,0 +1,56 @@
+/* eslint-disable camelcase -- ... */
+import { z } from 'zod';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useNavigate } from 'react-router-dom';
+import { t } from 'i18next';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { routerPaths } from '@/router/router-paths';
+
+export const sendResetLinkEmailDtoSchema = z.object({
+ email: z
+ .string()
+ .min(1, t('worker.sendResetLinkForm.noEmailError'))
+ .email(t('worker.sendResetLinkForm.invalidEmailError')),
+});
+
+export type SendResetLinkEmail = z.infer;
+
+export const sendResetLinkHcaptchaDtoSchema = z.object({
+ h_captcha_token: z.string(),
+});
+
+export type SendResetLinkHcaptcha = z.infer<
+ typeof sendResetLinkHcaptchaDtoSchema
+>;
+
+export const sendResetLinkDtoSchema = sendResetLinkEmailDtoSchema.merge(
+ sendResetLinkHcaptchaDtoSchema
+);
+
+export type SendResetLinkDto = SendResetLinkEmail & SendResetLinkHcaptcha;
+
+const SendResetLinkSuccessResponseSchema = z.unknown();
+
+function sendResetLinkMutationFn(data: SendResetLinkDto) {
+ return apiClient(apiPaths.worker.sendResetLink.path, {
+ successSchema: SendResetLinkSuccessResponseSchema,
+ options: { method: 'POST', body: JSON.stringify(data) },
+ });
+}
+
+export function useSendResetLinkMutation() {
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
+
+ return useMutation({
+ mutationFn: sendResetLinkMutationFn,
+ onSuccess: async (_, { email }) => {
+ navigate(routerPaths.worker.sendResetLinkSuccess, { state: { email } });
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/sign-in.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/sign-in.ts
new file mode 100644
index 0000000000..a5e142e4f8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/sign-in.ts
@@ -0,0 +1,59 @@
+import { z } from 'zod';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useNavigate } from 'react-router-dom';
+import { t } from 'i18next';
+// eslint-disable-next-line import/no-cycle -- cause by refresh token retry
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { routerPaths } from '@/router/router-paths';
+import { useAuth } from '@/auth/use-auth';
+
+export const signInDtoSchema = z.object({
+ email: z.string().email(t('validation.invalidEmail')),
+ password: z
+ .string()
+ .min(1, t('validation.passwordMissing'))
+ .max(50, t('validation.max', { count: 50 })),
+ // eslint-disable-next-line camelcase -- export vite config
+ h_captcha_token: z.string().min(1, t('validation.captcha')).default('token'),
+});
+
+export type SignInDto = z.infer;
+
+export const signInSuccessResponseSchema = z.object({
+ // eslint-disable-next-line camelcase -- data from api
+ access_token: z.string(),
+ // eslint-disable-next-line camelcase -- data from api
+ refresh_token: z.string(),
+});
+
+export type SignInSuccessResponse = z.infer;
+
+function signInMutationFn(data: SignInDto) {
+ return apiClient(apiPaths.worker.signIn.path, {
+ successSchema: signInSuccessResponseSchema,
+ options: {
+ method: 'POST',
+ body: JSON.stringify(data),
+ },
+ });
+}
+
+export function useSignInMutation() {
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
+ const { signIn } = useAuth();
+
+ return useMutation({
+ mutationFn: signInMutationFn,
+ onSuccess: async (data) => {
+ signIn(data);
+ navigate(routerPaths.worker.profile);
+ window.location.reload();
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/sign-up.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/sign-up.ts
new file mode 100644
index 0000000000..db3c2aaf0c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/sign-up.ts
@@ -0,0 +1,64 @@
+import { z } from 'zod';
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { useNavigate } from 'react-router-dom';
+import { t } from 'i18next';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import { routerPaths } from '@/router/router-paths';
+import { passwordRegex } from '@/shared/helpers/regex';
+
+export const signUpDtoSchema = z
+ .object({
+ email: z.string().email(t('validation.invalidEmail')),
+ // eslint-disable-next-line camelcase -- export vite config
+ h_captcha_token: z
+ .string()
+ .min(1, t('validation.captcha'))
+ .default('token'),
+ })
+ .and(
+ z
+ .object({
+ password: z
+ .string()
+ .max(50, t('validation.max', { count: 50 }))
+ .regex(passwordRegex, t('validation.passwordWeak')),
+ confirmPassword: z
+ .string()
+ .min(1, t('validation.required'))
+ .max(50, t('validation.max', { count: 50 })),
+ })
+ .refine(({ password, confirmPassword }) => confirmPassword === password, {
+ message: t('validation.passwordMismatch'),
+ path: ['confirmPassword'],
+ })
+ );
+
+export type SignUpDto = z.infer;
+
+const signUpSuccessResponseSchema = z.unknown();
+
+async function signUpMutationFn(data: Omit) {
+ await apiClient(apiPaths.worker.signUp.path, {
+ successSchema: signUpSuccessResponseSchema,
+ options: { method: 'POST', body: JSON.stringify(data) },
+ });
+}
+
+export function useSignUpMutation() {
+ const queryClient = useQueryClient();
+ const navigate = useNavigate();
+
+ return useMutation({
+ mutationFn: signUpMutationFn,
+ onSuccess: async (_, { email }) => {
+ navigate(routerPaths.worker.verifyEmail, {
+ state: { routerState: { email } },
+ });
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/solve-hcaptcha.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/solve-hcaptcha.ts
new file mode 100644
index 0000000000..f51da2da50
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/solve-hcaptcha.ts
@@ -0,0 +1,38 @@
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { z } from 'zod';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import type { ResponseError } from '@/shared/types/global.type';
+
+function solveHCaptcha({ token }: { token: string }) {
+ return apiClient(apiPaths.worker.verifyHCaptchaLabeling, {
+ successSchema: z.unknown(),
+ authenticated: true,
+ options: { method: 'POST', body: JSON.stringify({ token }) },
+ });
+}
+
+export function useSolveHCaptchaMutation(callbacks?: {
+ onSuccess?: (() => void) | (() => Promise);
+ onError?:
+ | ((error: ResponseError) => void)
+ | ((error: ResponseError) => Promise);
+}) {
+ const queryClient = useQueryClient();
+
+ return useMutation({
+ mutationFn: solveHCaptcha,
+ onSuccess: async () => {
+ if (callbacks?.onSuccess) {
+ await callbacks.onSuccess();
+ }
+ await queryClient.invalidateQueries();
+ },
+ onError: async (error) => {
+ if (callbacks?.onError) {
+ await callbacks.onError(error);
+ }
+ await queryClient.invalidateQueries();
+ },
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/use-register-address-on-chain.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/use-register-address-on-chain.ts
new file mode 100644
index 0000000000..b1724815f4
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/use-register-address-on-chain.ts
@@ -0,0 +1,66 @@
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import type { JsonRpcSigner } from 'ethers';
+import { t } from 'i18next';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { ethKvStoreSetBulk } from '@/smart-contracts/EthKVStore/eth-kv-store-set-bulk';
+import { getContractAddress } from '@/smart-contracts/get-contract-address';
+import type { SignedAddressSuccess } from '@/api/servieces/worker/get-signed-address';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+import { checkNetwork } from '@/smart-contracts/check-network';
+
+async function registerAddressInKVStore({
+ key,
+ value,
+ signer,
+ chainId,
+}: {
+ key: string;
+ value: string;
+ signer?: JsonRpcSigner;
+ chainId: number;
+}) {
+ const contractAddress = getContractAddress({
+ contractName: 'EthKVStore',
+ });
+
+ await ethKvStoreSetBulk({
+ keys: [key],
+ values: [value],
+ signer,
+ chainId,
+ contractAddress,
+ });
+}
+
+export function useRegisterAddressOnChainMutation() {
+ const queryClient = useQueryClient();
+ const { user } = useAuthenticatedUser();
+ const { web3ProviderMutation, chainId, address } = useWalletConnect();
+
+ return useMutation({
+ mutationFn: async (data: SignedAddressSuccess) => {
+ const network = await web3ProviderMutation.data?.provider.getNetwork();
+
+ if (!network) {
+ throw new Error('No network');
+ }
+ checkNetwork(network);
+ if (address?.toLowerCase() !== user.wallet_address?.toLowerCase()) {
+ throw new Error(t('worker.profile.wrongWalletAddress'));
+ }
+
+ await registerAddressInKVStore({
+ ...data,
+ signer: web3ProviderMutation.data?.signer,
+ chainId: chainId || -1,
+ });
+ },
+ onSuccess: async () => {
+ await queryClient.invalidateQueries();
+ },
+ onError: async () => {
+ await queryClient.invalidateQueries();
+ },
+ mutationKey: [user.wallet_address, address],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/api/servieces/worker/use-register-address.ts b/packages/apps/human-app/frontend/src/api/servieces/worker/use-register-address.ts
new file mode 100644
index 0000000000..cb50422fe5
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/api/servieces/worker/use-register-address.ts
@@ -0,0 +1,72 @@
+import { useMutation, useQueryClient } from '@tanstack/react-query';
+import { z } from 'zod';
+import { t } from 'i18next';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { apiClient } from '@/api/api-client';
+import { apiPaths } from '@/api/api-paths';
+import {
+ PrepareSignatureType,
+ prepareSignature,
+} from '@/api/servieces/common/prepare-signature';
+import type { ResponseError } from '@/shared/types/global.type';
+import { useGetAccessTokenMutation } from '@/api/servieces/common/get-access-token';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+
+const RegisterAddressSuccessSchema = z.unknown();
+
+export const registerAddress = (address: string, signature: string) => {
+ return apiClient(apiPaths.worker.registerAddress.path, {
+ authenticated: true,
+ successSchema: RegisterAddressSuccessSchema,
+ options: {
+ method: 'POST',
+ body: JSON.stringify({ address, signature }),
+ },
+ });
+};
+
+export function useRegisterAddressMutation(callbacks?: {
+ onSuccess?: (() => void) | (() => Promise);
+ onError?:
+ | ((error: ResponseError) => void)
+ | ((error: ResponseError) => Promise);
+}) {
+ const queryClient = useQueryClient();
+ const { user } = useAuthenticatedUser();
+ const { mutateAsync: getAccessTokenMutation } = useGetAccessTokenMutation();
+
+ const { address, signMessage } = useWalletConnect();
+ return useMutation({
+ mutationFn: async () => {
+ if (!address) {
+ throw new Error(t('errors.unknown'));
+ }
+ const dataToSign = await prepareSignature({
+ address,
+ type: PrepareSignatureType.RegisterAddress,
+ });
+ const messageToSign = JSON.stringify(dataToSign);
+ const signature = await signMessage(messageToSign);
+
+ if (!signature) {
+ throw new Error(t('errors.unknown'));
+ }
+
+ await registerAddress(address, signature);
+ await getAccessTokenMutation('web2');
+ },
+ onSuccess: async () => {
+ if (callbacks?.onSuccess) {
+ await callbacks.onSuccess();
+ }
+ await queryClient.invalidateQueries();
+ },
+ onError: async (error) => {
+ if (callbacks?.onError) {
+ await callbacks.onError(error);
+ }
+ await queryClient.invalidateQueries();
+ },
+ mutationKey: [user.wallet_address],
+ });
+}
diff --git a/packages/apps/human-app/frontend/src/assets/icons/back-arrow.svg b/packages/apps/human-app/frontend/src/assets/icons/back-arrow.svg
new file mode 100644
index 0000000000..1496ec100e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/back-arrow.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/chat.svg b/packages/apps/human-app/frontend/src/assets/icons/chat.svg
new file mode 100644
index 0000000000..f75eab9760
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/chat.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/checkmark-icon.svg b/packages/apps/human-app/frontend/src/assets/icons/checkmark-icon.svg
new file mode 100644
index 0000000000..645514e815
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/checkmark-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/filters-button-icon.svg b/packages/apps/human-app/frontend/src/assets/icons/filters-button-icon.svg
new file mode 100644
index 0000000000..232d851193
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/filters-button-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/filters-icon.svg b/packages/apps/human-app/frontend/src/assets/icons/filters-icon.svg
new file mode 100644
index 0000000000..724837a70a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/filters-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/hand.svg b/packages/apps/human-app/frontend/src/assets/icons/hand.svg
new file mode 100644
index 0000000000..ba2c2e4e07
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/hand.svg
@@ -0,0 +1,92 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/help.svg b/packages/apps/human-app/frontend/src/assets/icons/help.svg
new file mode 100644
index 0000000000..ae8c2ef700
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/help.svg
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/discord.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/discord.svg
new file mode 100644
index 0000000000..ee9689095f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/discord.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/logo.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/logo.svg
new file mode 100644
index 0000000000..40ae9fc71a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/logo.svg
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/mobile-header.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/mobile-header.svg
new file mode 100644
index 0000000000..9e2dd04b78
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/mobile-header.svg
@@ -0,0 +1,114 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/user.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/user.svg
new file mode 100644
index 0000000000..6d1000e608
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/user.svg
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/work.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/work.svg
new file mode 100644
index 0000000000..4602c220fe
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-homepage/work.svg
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-human-logo/human-logo-circle.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-human-logo/human-logo-circle.svg
new file mode 100644
index 0000000000..fcb3b4ddb1
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-human-logo/human-logo-circle.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-human-logo/human-logo.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-human-logo/human-logo.svg
new file mode 100644
index 0000000000..f2739b8093
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-human-logo/human-logo.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/icons-navbar/human-logo-navbar.svg b/packages/apps/human-app/frontend/src/assets/icons/icons-navbar/human-logo-navbar.svg
new file mode 100644
index 0000000000..473b53e255
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/icons-navbar/human-logo-navbar.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/info.svg b/packages/apps/human-app/frontend/src/assets/icons/info.svg
new file mode 100644
index 0000000000..252d7ed1f0
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/info.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/locker-icon.svg b/packages/apps/human-app/frontend/src/assets/icons/locker-icon.svg
new file mode 100644
index 0000000000..80f66da5b8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/locker-icon.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/profile-icon.svg b/packages/apps/human-app/frontend/src/assets/icons/profile-icon.svg
new file mode 100644
index 0000000000..0a540ae68a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/profile-icon.svg
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/refresh.svg b/packages/apps/human-app/frontend/src/assets/icons/refresh.svg
new file mode 100644
index 0000000000..7590498e9c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/refresh.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/sort-arrow.svg b/packages/apps/human-app/frontend/src/assets/icons/sort-arrow.svg
new file mode 100644
index 0000000000..9364f82a04
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/sort-arrow.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/user-filled.svg b/packages/apps/human-app/frontend/src/assets/icons/user-filled.svg
new file mode 100644
index 0000000000..ea37160a77
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/user-filled.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/user-outlined.svg b/packages/apps/human-app/frontend/src/assets/icons/user-outlined.svg
new file mode 100644
index 0000000000..49c8752f63
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/user-outlined.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/user-secondary.svg b/packages/apps/human-app/frontend/src/assets/icons/user-secondary.svg
new file mode 100644
index 0000000000..303b047f37
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/user-secondary.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/work-secondary.svg b/packages/apps/human-app/frontend/src/assets/icons/work-secondary.svg
new file mode 100644
index 0000000000..065a03d862
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/work-secondary.svg
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/assets/icons/work.svg b/packages/apps/human-app/frontend/src/assets/icons/work.svg
new file mode 100644
index 0000000000..cd6b13c4de
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/assets/icons/work.svg
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/packages/apps/human-app/frontend/src/auth-web3/require-wallet-connect.tsx b/packages/apps/human-app/frontend/src/auth-web3/require-wallet-connect.tsx
new file mode 100644
index 0000000000..55ebd84f27
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth-web3/require-wallet-connect.tsx
@@ -0,0 +1,34 @@
+import { useLocation, Navigate } from 'react-router-dom';
+import { createContext } from 'react';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+import type { WalletConnectContextConnectedAccount } from '@/contexts/wallet-connect';
+import { routerPaths } from '@/router/router-paths';
+import { PageCardLoader } from '@/components/ui/page-card';
+
+export const AuthWeb3Context =
+ createContext(null);
+
+export function RequireWalletConnect({ children }: { children: JSX.Element }) {
+ const walletConnect = useWalletConnect();
+ const location = useLocation();
+
+ if (walletConnect.initializing) {
+ return ;
+ }
+
+ if (!walletConnect.isConnected) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/auth-web3/require-web3-auth.tsx b/packages/apps/human-app/frontend/src/auth-web3/require-web3-auth.tsx
new file mode 100644
index 0000000000..83957b8a4b
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth-web3/require-web3-auth.tsx
@@ -0,0 +1,30 @@
+import { useLocation, Navigate } from 'react-router-dom';
+import { createContext } from 'react';
+import { routerPaths } from '@/router/router-paths';
+import type { Web3AuthenticatedUserContextType } from '@/auth-web3/web3-auth-context';
+import { PageCardLoader } from '@/components/ui/page-card';
+import { useWeb3Auth } from '@/auth-web3/use-web3-auth';
+
+export const Web3AuthenticatedUserContext =
+ createContext(null);
+
+export function RequireWeb3Auth({ children }: { children: JSX.Element }) {
+ const web3Auth = useWeb3Auth();
+ const location = useLocation();
+
+ if (web3Auth.status === 'loading') {
+ return ;
+ }
+
+ if (!web3Auth.user) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/auth-web3/use-connected-wallet.tsx b/packages/apps/human-app/frontend/src/auth-web3/use-connected-wallet.tsx
new file mode 100644
index 0000000000..1cbf452ebe
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth-web3/use-connected-wallet.tsx
@@ -0,0 +1,14 @@
+import { useContext } from 'react';
+import { AuthWeb3Context } from '@/auth-web3/require-wallet-connect';
+
+export const useConnectedWallet = () => {
+ const context = useContext(AuthWeb3Context);
+
+ if (!context) {
+ throw new Error(
+ 'Cannot use context of useConnectedWallet. Component is not included in protectedWeb3Routes'
+ );
+ }
+
+ return context;
+};
diff --git a/packages/apps/human-app/frontend/src/auth-web3/use-web3-auth.tsx b/packages/apps/human-app/frontend/src/auth-web3/use-web3-auth.tsx
new file mode 100644
index 0000000000..5ec39935eb
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth-web3/use-web3-auth.tsx
@@ -0,0 +1,12 @@
+import { useContext } from 'react';
+import { Web3AuthContext } from '@/auth-web3/web3-auth-context';
+
+export function useWeb3Auth() {
+ const context = useContext(Web3AuthContext);
+
+ if (!context) {
+ throw new Error('No context for useWeb3Auth');
+ }
+
+ return context;
+}
diff --git a/packages/apps/human-app/frontend/src/auth-web3/use-web3-authenticated-user.tsx b/packages/apps/human-app/frontend/src/auth-web3/use-web3-authenticated-user.tsx
new file mode 100644
index 0000000000..d5609ea59a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth-web3/use-web3-authenticated-user.tsx
@@ -0,0 +1,14 @@
+import { useContext } from 'react';
+import { Web3AuthenticatedUserContext } from '@/auth-web3/require-web3-auth';
+
+export function useWeb3AuthenticatedUser() {
+ const context = useContext(Web3AuthenticatedUserContext);
+
+ if (!context) {
+ throw new Error(
+ 'Cannot use context of useWeb3AuthenticatedUser. Component is not included in web3AuthProtectedRoutes'
+ );
+ }
+
+ return context;
+}
diff --git a/packages/apps/human-app/frontend/src/auth-web3/wallet-connect-modal.tsx b/packages/apps/human-app/frontend/src/auth-web3/wallet-connect-modal.tsx
new file mode 100644
index 0000000000..de38fd86ca
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth-web3/wallet-connect-modal.tsx
@@ -0,0 +1,78 @@
+import { t } from 'i18next';
+import { Grid, Typography } from '@mui/material';
+import { Trans } from 'react-i18next';
+import { Link } from 'react-router-dom';
+import { useEffect } from 'react';
+import { Button } from '@/components/ui/button';
+import { ConnectWalletBtn } from '@/components/ui/connect-wallet-btn';
+import { useModalStore } from '@/components/ui/modal/modal.store';
+import { env } from '@/shared/env';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+
+export function WalletConnectModal() {
+ const { closeModal } = useModalStore();
+ const { isConnected } = useWalletConnect();
+
+ useEffect(() => {
+ if (isConnected) {
+ closeModal();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- ...
+ }, [isConnected]);
+
+ return (
+
+
+ {t('walletConnectModal.header')}
+
+
+
+ ),
+ }}
+ i18nKey="walletConnectModal.paragraph"
+ />
+
+
+ {t('walletConnectModal.connectBtn')}
+
+ {
+ closeModal();
+ }}
+ variant="outlined"
+ >
+ {t('walletConnectModal.cancelBtn')}
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/auth-web3/web3-auth-context.tsx b/packages/apps/human-app/frontend/src/auth-web3/web3-auth-context.tsx
new file mode 100644
index 0000000000..fb6c117595
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth-web3/web3-auth-context.tsx
@@ -0,0 +1,117 @@
+/* eslint-disable camelcase -- ...*/
+import { useState, createContext, useEffect } from 'react';
+import { jwtDecode } from 'jwt-decode';
+import { z } from 'zod';
+import type { SignInSuccessResponse } from '@/api/servieces/worker/sign-in';
+import { browserAuthProvider } from '@/shared/helpers/browser-auth-provider';
+
+const web3userDataSchema = z.object({
+ userId: z.number(),
+ wallet_address: z.string(),
+ reputation_network: z.string(),
+ exp: z.number(),
+ status: z.string().nullable().optional(),
+});
+
+export type Web3UserData = z.infer;
+
+type AuthStatus = 'loading' | 'error' | 'success' | 'idle';
+export interface Web3AuthenticatedUserContextType {
+ user: Web3UserData;
+ status: AuthStatus;
+ signOut: () => void;
+ signIn: (singIsSuccess: SignInSuccessResponse) => void;
+ updateUserData: (updateUserDataPayload: Partial) => void;
+}
+
+interface Web3UnauthenticatedUserContextType {
+ user: null;
+ status: AuthStatus;
+ signOut: () => void;
+ signIn: (singIsSuccess: SignInSuccessResponse) => void;
+}
+
+export const Web3AuthContext = createContext<
+ Web3AuthenticatedUserContextType | Web3UnauthenticatedUserContextType | null
+>(null);
+
+export function Web3AuthProvider({ children }: { children: React.ReactNode }) {
+ const [web3AuthState, setWeb3AuthState] = useState<{
+ user: Web3UserData | null;
+ status: AuthStatus;
+ }>({ user: null, status: 'loading' });
+ const updateUserData = (updateUserDataPayload: Partial) => {
+ setWeb3AuthState((state) => {
+ if (!state.user) {
+ return state;
+ }
+
+ const newUserData = {
+ ...state.user,
+ ...updateUserDataPayload,
+ };
+ browserAuthProvider.setUserData(newUserData);
+
+ return {
+ ...state,
+ user: newUserData,
+ };
+ });
+ };
+
+ const handleSignIn = () => {
+ try {
+ const accessToken = browserAuthProvider.getAccessToken();
+ const authType = browserAuthProvider.getAuthType();
+
+ if (!accessToken || authType !== 'web3') {
+ setWeb3AuthState({ user: null, status: 'idle' });
+ return;
+ }
+ const userData = jwtDecode(accessToken);
+ const validUserData = web3userDataSchema.parse(userData);
+ setWeb3AuthState({ user: validUserData, status: 'success' });
+ } catch (e) {
+ // eslint-disable-next-line no-console -- ...
+ console.error('Invalid Jwt payload:', e);
+ browserAuthProvider.signOut();
+ setWeb3AuthState({ user: null, status: 'error' });
+ }
+ };
+ // TODO correct interface of singIsSuccess from auth/web3/signing
+ const signIn = (singIsSuccess: SignInSuccessResponse) => {
+ browserAuthProvider.signIn(singIsSuccess, 'web3');
+ handleSignIn();
+ };
+
+ const signOut = () => {
+ setWeb3AuthState({ user: null, status: 'idle' });
+ };
+
+ useEffect(() => {
+ handleSignIn();
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/auth/auth-context.tsx b/packages/apps/human-app/frontend/src/auth/auth-context.tsx
new file mode 100644
index 0000000000..62fe16a0d0
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth/auth-context.tsx
@@ -0,0 +1,133 @@
+/* eslint-disable camelcase -- ... */
+import { useState, createContext, useEffect } from 'react';
+import { jwtDecode } from 'jwt-decode';
+import { z } from 'zod';
+import type { SignInSuccessResponse } from '@/api/servieces/worker/sign-in';
+import { browserAuthProvider } from '@/shared/helpers/browser-auth-provider';
+
+const extendableUserDataSchema = z.object({
+ site_key: z.string().optional().nullable(),
+ kyc_status: z.string().optional().nullable(),
+ wallet_address: z.string().optional().nullable(),
+ status: z.string().optional().nullable(),
+});
+
+const userDataSchema = z
+ .object({
+ email: z.string(),
+ userId: z.number(),
+ reputation_network: z.string(),
+ email_notifications: z.boolean().optional(), // TODO that should be verified when email notifications feature is done
+ exp: z.number(),
+ })
+ .merge(extendableUserDataSchema);
+
+export type UserData = z.infer;
+export type UpdateUserDataPayload = z.infer;
+
+type AuthStatus = 'loading' | 'error' | 'success' | 'idle';
+export interface AuthenticatedUserContextType {
+ user: UserData;
+ status: AuthStatus;
+ signOut: () => void;
+ signIn: (singIsSuccess: SignInSuccessResponse) => void;
+ updateUserData: (updateUserDataPayload: UpdateUserDataPayload) => void;
+}
+
+interface UnauthenticatedUserContextType {
+ user: null;
+ status: AuthStatus;
+ signOut: () => void;
+ signIn: (singIsSuccess: SignInSuccessResponse) => void;
+}
+
+export const AuthContext = createContext<
+ AuthenticatedUserContextType | UnauthenticatedUserContextType | null
+>(null);
+
+export function AuthProvider({ children }: { children: React.ReactNode }) {
+ const [authState, setAuthState] = useState<{
+ user: UserData | null;
+ status: AuthStatus;
+ }>({ user: null, status: 'loading' });
+ const updateUserData = (updateUserDataPayload: UpdateUserDataPayload) => {
+ setAuthState((state) => {
+ if (!state.user) {
+ return state;
+ }
+
+ const newUserData = {
+ ...state.user,
+ ...updateUserDataPayload,
+ };
+ browserAuthProvider.setUserData(newUserData);
+
+ return {
+ ...state,
+ user: newUserData,
+ };
+ });
+ };
+
+ const handleSignIn = () => {
+ try {
+ const accessToken = browserAuthProvider.getAccessToken();
+ const authType = browserAuthProvider.getAuthType();
+ const savedUserData = browserAuthProvider.getUserData();
+
+ if (!accessToken || authType !== 'web2') {
+ setAuthState({ user: null, status: 'idle' });
+ return;
+ }
+ const userData = jwtDecode(accessToken);
+ const userDataWithSavedData = savedUserData.data
+ ? { ...userData, ...savedUserData.data }
+ : userData;
+
+ const validUserData = userDataSchema.parse(userDataWithSavedData);
+ setAuthState({ user: validUserData, status: 'success' });
+ } catch (e) {
+ // eslint-disable-next-line no-console -- ...
+ console.error('Invalid Jwt payload:', e);
+ browserAuthProvider.signOut();
+ setAuthState({ user: null, status: 'error' });
+ }
+ };
+
+ const signIn = (singIsSuccess: SignInSuccessResponse) => {
+ browserAuthProvider.signIn(singIsSuccess, 'web2');
+ handleSignIn();
+ };
+
+ const signOut = () => {
+ browserAuthProvider.signOut();
+ setAuthState({ user: null, status: 'idle' });
+ };
+
+ useEffect(() => {
+ handleSignIn();
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/auth/require-auth.tsx b/packages/apps/human-app/frontend/src/auth/require-auth.tsx
new file mode 100644
index 0000000000..f4d42d2419
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth/require-auth.tsx
@@ -0,0 +1,30 @@
+import { useLocation, Navigate } from 'react-router-dom';
+import { createContext } from 'react';
+import { useAuth } from '@/auth/use-auth';
+import { routerPaths } from '@/router/router-paths';
+import type { AuthenticatedUserContextType } from '@/auth/auth-context';
+import { PageCardLoader } from '@/components/ui/page-card';
+
+export const AuthenticatedUserContext =
+ createContext(null);
+
+export function RequireAuth({ children }: { children: JSX.Element }) {
+ const auth = useAuth();
+ const location = useLocation();
+
+ if (auth.status === 'loading') {
+ return ;
+ }
+
+ if (!auth.user) {
+ return (
+
+ );
+ }
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/auth/use-auth.ts b/packages/apps/human-app/frontend/src/auth/use-auth.ts
new file mode 100644
index 0000000000..e3b25488bf
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth/use-auth.ts
@@ -0,0 +1,12 @@
+import { useContext } from 'react';
+import { AuthContext } from '@/auth/auth-context';
+
+export function useAuth() {
+ const context = useContext(AuthContext);
+
+ if (!context) {
+ throw new Error('No context for useAuth');
+ }
+
+ return context;
+}
diff --git a/packages/apps/human-app/frontend/src/auth/use-authenticated-user.tsx b/packages/apps/human-app/frontend/src/auth/use-authenticated-user.tsx
new file mode 100644
index 0000000000..1062be6830
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/auth/use-authenticated-user.tsx
@@ -0,0 +1,14 @@
+import { useContext } from 'react';
+import { AuthenticatedUserContext } from '@/auth/require-auth';
+
+export function useAuthenticatedUser() {
+ const context = useContext(AuthenticatedUserContext);
+
+ if (!context) {
+ throw new Error(
+ 'Cannot use context of useAuthenticatedUser. Component is not included in protectedRoutes'
+ );
+ }
+
+ return context;
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/checkbox.tsx b/packages/apps/human-app/frontend/src/components/data-entry/checkbox.tsx
new file mode 100644
index 0000000000..30fa569b82
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/checkbox.tsx
@@ -0,0 +1,42 @@
+import { Controller } from 'react-hook-form';
+import type { CheckboxProps } from '@mui/material/Checkbox';
+import CheckboxMui from '@mui/material/Checkbox';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import Stack from '@mui/material/Stack';
+import Typography from '@mui/material/Typography';
+import { colorPalette } from '@/styles/color-palette';
+
+interface InputProps extends Omit {
+ name: string;
+ label?: string;
+}
+
+export function Checkbox({ name, label = '', ...rest }: InputProps) {
+ return (
+ (
+
+
+ }
+ label={{label} }
+ />
+
+ )}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/form-example.tsx b/packages/apps/human-app/frontend/src/components/data-entry/form-example.tsx
new file mode 100644
index 0000000000..520a768715
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/form-example.tsx
@@ -0,0 +1,189 @@
+import { useState } from 'react';
+import type { SubmitHandler } from 'react-hook-form';
+import { useForm, FormProvider } from 'react-hook-form';
+import Grid from '@mui/material/Grid';
+import Box from '@mui/material/Box';
+import Typography from '@mui/material/Typography';
+import Stack from '@mui/material/Stack';
+import { Input } from '@/components/data-entry/input';
+import { Select } from '@/components/data-entry/select';
+import { RadioButton } from '@/components/data-entry/radio-button';
+import { Checkbox } from '@/components/data-entry/checkbox';
+import { Slider } from '@/components/data-entry/slider';
+import { MultiSelect } from '@/components/data-entry/multi-select';
+import { Password } from '@/components/data-entry/password/password';
+
+export interface Inputs {
+ name: string;
+ surname: string;
+ email: string;
+ firstCheckbox: boolean;
+ slider: number;
+ month: string;
+}
+
+const names = [
+ 'Oliver Hansen',
+ 'Van Henry',
+ 'April Tucker',
+ 'Ralph Hubbard',
+ 'Omar Alexander',
+ 'Carlos Abbott',
+ 'Miriam Wagner',
+ 'Bradley Wilkerson',
+ 'Virginia Andrews',
+ 'Kelly Snyder',
+];
+
+const accounts = [
+ {
+ id: 1,
+ name: 'PL76114011245044546199764000',
+ value: 'PL76114011245044546199764000',
+ },
+ {
+ id: 2,
+ name: 'PL76114011245044546199761111',
+ value: 'PL76114011245044546199761111',
+ },
+ {
+ id: 2,
+ name: 'PL76114011245044546199764117',
+ value: 'PL76114011245044546199764117',
+ },
+];
+
+const MIN = 3000;
+const MAX = 50000;
+
+function CustomMarks({ min, max }: { min: number; max: number }) {
+ return (
+
+ min. {min} PLN
+ max. {max} PLN
+
+ );
+}
+
+export function FormExample() {
+ const [values, setValues] = useState();
+ const methods = useForm({
+ defaultValues: {
+ name: '',
+ surname: '',
+ email: '',
+ },
+ });
+
+ const onSubmit: SubmitHandler = (data) => {
+ const formData = {
+ ...data,
+ };
+ setValues(formData);
+ };
+
+ return (
+ <>
+
+
+
+ {values ? (
+
+ Name: {values.name}
+ Surname: {values.surname}
+ Email: {values.email}
+ Slider: {values.slider}
+ Month: {values.month}
+
+ ) : null}
+ >
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/input-masks/human-currency-input-mask.tsx b/packages/apps/human-app/frontend/src/components/data-entry/input-masks/human-currency-input-mask.tsx
new file mode 100644
index 0000000000..140a41b2d2
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/input-masks/human-currency-input-mask.tsx
@@ -0,0 +1,39 @@
+import { t } from 'i18next';
+import type { ForwardRefExoticComponent, RefAttributes } from 'react';
+import { forwardRef } from 'react';
+import type { NumericFormatProps } from 'react-number-format';
+import { NumericFormat } from 'react-number-format';
+
+interface CustomProps {
+ onChange: (event: { target: { name: string; value: string } }) => void;
+ name: string;
+}
+
+export type InputMaskComponent = ForwardRefExoticComponent<
+ CustomProps & RefAttributes
+>;
+
+export const HumanCurrencyInputMask = forwardRef<
+ NumericFormatProps,
+ CustomProps
+>(function NumericFormatCustom(props, ref) {
+ const { onChange, ...other } = props;
+
+ return (
+ {
+ onChange({
+ target: {
+ name: props.name,
+ value: values.value,
+ },
+ });
+ }}
+ prefix={t('inputMasks.plusPrefix')}
+ suffix={t('inputMasks.humanCurrencySuffix')}
+ valueIsNumericString
+ />
+ );
+});
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/input-masks/input-masks.ts b/packages/apps/human-app/frontend/src/components/data-entry/input-masks/input-masks.ts
new file mode 100644
index 0000000000..8a2af068a2
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/input-masks/input-masks.ts
@@ -0,0 +1,9 @@
+import { HumanCurrencyInputMask } from '@/components/data-entry/input-masks/human-currency-input-mask';
+import { PercentsInputMask } from '@/components/data-entry/input-masks/percents-input-mask';
+
+export const InputMasks = {
+ HumanCurrencyInputMask,
+ PercentsInputMask,
+};
+
+export type InputMask = keyof typeof InputMasks;
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/input-masks/percents-input-mask.tsx b/packages/apps/human-app/frontend/src/components/data-entry/input-masks/percents-input-mask.tsx
new file mode 100644
index 0000000000..2985abf67d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/input-masks/percents-input-mask.tsx
@@ -0,0 +1,37 @@
+import { t } from 'i18next';
+import type { ForwardRefExoticComponent, RefAttributes } from 'react';
+import { forwardRef } from 'react';
+import type { NumericFormatProps } from 'react-number-format';
+import { NumericFormat } from 'react-number-format';
+
+interface CustomProps {
+ onChange: (event: { target: { name: string; value: string } }) => void;
+ name: string;
+}
+
+export type InputMaskComponent = ForwardRefExoticComponent<
+ CustomProps & RefAttributes
+>;
+
+export const PercentsInputMask = forwardRef(
+ function NumericFormatCustom(props, ref) {
+ const { onChange, ...other } = props;
+
+ return (
+ {
+ onChange({
+ target: {
+ name: props.name,
+ value: values.value,
+ },
+ });
+ }}
+ suffix={t('inputMasks.percentSuffix')}
+ valueIsNumericString
+ />
+ );
+ }
+);
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/input.tsx b/packages/apps/human-app/frontend/src/components/data-entry/input.tsx
new file mode 100644
index 0000000000..c0f5a43180
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/input.tsx
@@ -0,0 +1,61 @@
+import { Controller } from 'react-hook-form';
+import type { TextFieldProps } from '@mui/material/TextField';
+import TextField from '@mui/material/TextField';
+import { Typography } from '@mui/material';
+import { colorPalette } from '@/styles/color-palette';
+import type { InputMask } from '@/components/data-entry/input-masks/input-masks';
+import { InputMasks } from '@/components/data-entry/input-masks/input-masks';
+
+export interface InputProps
+ extends Omit {
+ name: string;
+ label?: string;
+ autoComplete?: string;
+ customError?: React.ReactNode;
+ mask?: InputMask;
+}
+
+export function Input({
+ name,
+ autoComplete,
+ label,
+ customError,
+ mask,
+ ...rest
+}: InputProps) {
+ return (
+ (
+
+ {customError ? customError : fieldState.error?.message}
+
+ }
+ label={label}
+ name={name}
+ variant="outlined"
+ {...rest}
+ />
+ )}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/multi-select.tsx b/packages/apps/human-app/frontend/src/components/data-entry/multi-select.tsx
new file mode 100644
index 0000000000..ff14dfdc3a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/multi-select.tsx
@@ -0,0 +1,149 @@
+import { Controller, useFormContext } from 'react-hook-form';
+import type { ControllerRenderProps, FieldValues } from 'react-hook-form';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import type { SelectProps, SelectChangeEvent } from '@mui/material/Select';
+import MenuItem from '@mui/material/MenuItem';
+import InputLabel from '@mui/material/InputLabel';
+import Checkbox from '@mui/material/Checkbox';
+import ListItemText from '@mui/material/ListItemText';
+import { useTranslation } from 'react-i18next';
+import {
+ Box,
+ Chip,
+ Divider,
+ FormHelperText,
+ OutlinedInput,
+ Typography,
+} from '@mui/material';
+import CancelIcon from '@mui/icons-material/Cancel';
+import { colorPalette } from '@/styles/color-palette';
+
+interface MultiSelectProps extends Omit {
+ options: string[];
+ name: string;
+ label: string;
+}
+
+type FieldType = ControllerRenderProps;
+
+const CLEAR_ALL_VALUE = 'CLEAR_ALL_VALUE';
+const CHECK_ALL_VALUE = 'CHECK_ALL_VALUE';
+
+export function MultiSelect({
+ name,
+ options,
+ label,
+ ...props
+}: MultiSelectProps) {
+ const { t } = useTranslation();
+ const context = useFormContext();
+
+ const isFieldChecked = (field: FieldType, option: string) => {
+ if (Array.isArray(field.value)) {
+ return field.value.includes(option);
+ }
+ return false;
+ };
+
+ const onDelete = (value: string) => {
+ const currentValues = context.getValues()[name] as string[];
+
+ context.setValue(
+ name,
+ currentValues.filter((val) => {
+ return val !== value;
+ })
+ );
+ };
+
+ const renderValue = (selected: string[]) => (
+
+ {selected.map((value) => (
+ {
+ e.stopPropagation();
+ }}
+ />
+ }
+ key={value}
+ label={value}
+ onDelete={() => {
+ onDelete(value);
+ }}
+ />
+ ))}
+
+ );
+
+ const handleChange = (
+ event: SelectChangeEvent,
+ field: FieldType
+ ) => {
+ const value = event.target.value;
+
+ if (value.includes(CLEAR_ALL_VALUE)) {
+ context.setValue(name, []);
+ return;
+ }
+
+ if (
+ value[value.length - 1] === CHECK_ALL_VALUE &&
+ Array.isArray(field.value)
+ ) {
+ context.setValue(
+ name,
+ field.value.length === options.length ? [] : options
+ );
+ } else {
+ context.setValue(name, value);
+ }
+ };
+
+ return (
+ {
+ return (
+
+ {label}
+ }
+ {...field}
+ defaultValue={[]}
+ error={Boolean(fieldState.error)}
+ id={name}
+ labelId={`${name}-${label}`}
+ multiple
+ renderValue={renderValue}
+ {...props}
+ onChange={(event) => {
+ handleChange(event, field);
+ }}
+ >
+ {options.map((option) => (
+
+
+ {option}
+
+ ))}
+
+
+
+ {t('components.multiSelect.clearAll')}
+
+
+
+
+ {fieldState.error?.message}
+
+
+ );
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/password/password-check-label.tsx b/packages/apps/human-app/frontend/src/components/data-entry/password/password-check-label.tsx
new file mode 100644
index 0000000000..02206b63fd
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/password/password-check-label.tsx
@@ -0,0 +1,63 @@
+import type { z } from 'zod';
+import { Grid, Typography } from '@mui/material';
+import CancelIcon from '@mui/icons-material/Cancel';
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import { colorPalette } from '@/styles/color-palette';
+
+export interface PasswordCheck {
+ schema: z.ZodSchema;
+ requirementsLabel: string;
+}
+
+const getColor = (isSubmitted: boolean, isValid: boolean) => {
+ if (isSubmitted) {
+ if (isValid) {
+ return colorPalette.success.dark;
+ }
+ return colorPalette.error.main;
+ }
+
+ if (isValid) {
+ return colorPalette.success.dark;
+ }
+
+ return colorPalette.text.primary;
+};
+
+const getIcon = (isSubmitted: boolean, isValid: boolean) => {
+ if (isSubmitted) {
+ if (isValid) {
+ return ;
+ }
+ return ;
+ }
+
+ if (isValid) {
+ return ;
+ }
+ return ;
+};
+
+export function PasswordCheckLabel({
+ schema,
+ password,
+ requirementsLabel,
+ isSubmitted,
+}: PasswordCheck & { password: unknown; isSubmitted: boolean }) {
+ const isValid = schema.safeParse(password).success;
+
+ return (
+
+ {getIcon(isSubmitted, isValid)}
+
+ {requirementsLabel}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/password/password-checks.tsx b/packages/apps/human-app/frontend/src/components/data-entry/password/password-checks.tsx
new file mode 100644
index 0000000000..fb22cccf9a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/password/password-checks.tsx
@@ -0,0 +1,33 @@
+import { t } from 'i18next';
+import { z } from 'zod';
+import type { PasswordCheck } from '@/components/data-entry/password/password-check-label';
+import {
+ password8Chars,
+ passwordLowercase,
+ passwordNumeric,
+ passwordSpecialCharacter,
+ passwordUppercase,
+} from '@/shared/helpers/regex';
+
+export const passwordChecks: PasswordCheck[] = [
+ {
+ requirementsLabel: t('validation.password8Chars'),
+ schema: z.string().regex(password8Chars),
+ },
+ {
+ requirementsLabel: t('validation.passwordUppercase'),
+ schema: z.string().regex(passwordUppercase),
+ },
+ {
+ requirementsLabel: t('validation.passwordLowercase'),
+ schema: z.string().regex(passwordLowercase),
+ },
+ {
+ requirementsLabel: t('validation.passwordNumeric'),
+ schema: z.string().regex(passwordNumeric),
+ },
+ {
+ requirementsLabel: t('validation.passwordSpecialCharacter'),
+ schema: z.string().regex(passwordSpecialCharacter),
+ },
+];
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/password/password.tsx b/packages/apps/human-app/frontend/src/components/data-entry/password/password.tsx
new file mode 100644
index 0000000000..12bac3bc6c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/password/password.tsx
@@ -0,0 +1,105 @@
+import Visibility from '@mui/icons-material/Visibility';
+import VisibilityOff from '@mui/icons-material/VisibilityOff';
+import React, { useState } from 'react';
+import InputAdornment from '@mui/material/InputAdornment';
+import IconButton from '@mui/material/IconButton';
+import { Grid, Typography } from '@mui/material';
+import { useFormContext, useFormState } from 'react-hook-form';
+import { Input, type InputProps } from '@/components/data-entry/input';
+import {
+ PasswordCheckLabel,
+ type PasswordCheck,
+} from '@/components/data-entry/password/password-check-label';
+import { colorPalette } from '@/styles/color-palette';
+
+type CommonProps = InputProps & { type?: never };
+
+type PasswordProps =
+ | (CommonProps & { passwordCheckHeader?: never; passwordChecks?: never })
+ | (CommonProps & {
+ passwordCheckHeader: string;
+ passwordChecks: PasswordCheck[];
+ });
+
+export function Password({
+ passwordCheckHeader,
+ passwordChecks,
+ ...rest
+}: PasswordProps) {
+ const [showPassword, setShowPassword] = useState(false);
+ const { getValues, watch } = useFormContext();
+ const { isSubmitted } = useFormState();
+ watch(rest.name);
+ const password = getValues()[rest.name] as unknown;
+
+ const handleClickShowPassword = () => {
+ setShowPassword((show) => !show);
+ };
+
+ const handleMouseDownPassword = (
+ event: React.MouseEvent
+ ) => {
+ event.preventDefault();
+ };
+
+ const customError = passwordCheckHeader ? (
+
+
+ {passwordCheckHeader}
+
+
+ {passwordChecks.map((checks) => {
+ return (
+
+ );
+ })}
+
+
+ ) : null;
+
+ return (
+
+
+ {showPassword ? (
+
+ ) : (
+
+ )}
+
+
+ ),
+ }}
+ customError={customError}
+ onKeyDown={(e) => {
+ // ignore space
+ if (e.keyCode === 32) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }}
+ type={showPassword ? 'text' : 'password'}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/radio-button.tsx b/packages/apps/human-app/frontend/src/components/data-entry/radio-button.tsx
new file mode 100644
index 0000000000..8eba4cbd4f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/radio-button.tsx
@@ -0,0 +1,52 @@
+import { Controller } from 'react-hook-form';
+import type { RadioGroupProps as RadioGroupPropsMui } from '@mui/material/RadioGroup';
+import RadioGroup from '@mui/material/RadioGroup';
+import FormControl from '@mui/material/FormControl';
+import FormLabel from '@mui/material/FormLabel';
+import FormControlLabel from '@mui/material/FormControlLabel';
+import Radio from '@mui/material/Radio';
+import FormHelperText from '@mui/material/FormHelperText';
+
+interface RadioGroupProps extends Omit {
+ name: string;
+ ariaLabelledby?: string;
+ groupLabel?: string;
+ options: { label: string; value: string | number }[];
+}
+
+export function RadioButton({
+ name,
+ ariaLabelledby,
+ options,
+ groupLabel,
+ ...rest
+}: RadioGroupProps) {
+ return (
+ (
+
+ {groupLabel ? (
+ {groupLabel}
+ ) : null}
+
+ {options.map(({ label, value }) => (
+ }
+ key={value}
+ label={label}
+ value={value}
+ />
+ ))}
+
+ {fieldState.error?.message}
+
+ )}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/select.tsx b/packages/apps/human-app/frontend/src/components/data-entry/select.tsx
new file mode 100644
index 0000000000..e724f369ee
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/select.tsx
@@ -0,0 +1,62 @@
+import type { SelectProps } from '@mui/material/Select';
+import FormControl from '@mui/material/FormControl';
+import SelectMui from '@mui/material/Select';
+import MenuItem from '@mui/material/MenuItem';
+import { Controller } from 'react-hook-form';
+import InputLabel from '@mui/material/InputLabel';
+import FormHelperText from '@mui/material/FormHelperText';
+import { Chip } from '@/components/ui/chip';
+
+export interface OptionsProps {
+ id: number;
+ name: string;
+ value: string;
+}
+
+interface SelectComponentProps extends Omit {
+ options: OptionsProps[];
+ name: string;
+ label?: string;
+ ariaLabelledby?: string;
+ isChipRenderValue?: boolean;
+}
+
+export function Select({
+ ariaLabelledby,
+ name,
+ label,
+ options,
+ isChipRenderValue,
+ ...props
+}: SelectComponentProps) {
+ return (
+ (
+
+ {label ? {label} : null}
+
+ : undefined
+ }
+ >
+ {options.map((elem) => (
+
+ {elem.name}
+
+ ))}
+
+ {fieldState.error?.message}
+
+ )}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/data-entry/slider.tsx b/packages/apps/human-app/frontend/src/components/data-entry/slider.tsx
new file mode 100644
index 0000000000..adbd847c19
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/data-entry/slider.tsx
@@ -0,0 +1,40 @@
+import { Controller } from 'react-hook-form';
+import type { SliderProps } from '@mui/material/Slider';
+import SliderMui from '@mui/material/Slider';
+import type { ReactNode } from 'react';
+
+interface InputProps extends Omit {
+ max: number;
+ min: number;
+ step?: number;
+ name: string;
+ customMarks?: ReactNode;
+}
+
+export function Slider({
+ name,
+ max,
+ min,
+ step,
+ customMarks,
+ ...rest
+}: InputProps) {
+ return (
+ (
+ <>
+
+ {customMarks ? customMarks : null}
+ >
+ )}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/h-captcha.tsx b/packages/apps/human-app/frontend/src/components/h-captcha.tsx
new file mode 100644
index 0000000000..dd25240c25
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/h-captcha.tsx
@@ -0,0 +1,62 @@
+import { useEffect, useRef } from 'react';
+import HCaptcha from '@hcaptcha/react-hcaptcha';
+import { useFormContext } from 'react-hook-form';
+import { Typography } from '@mui/material';
+import { env } from '@/shared/env';
+import { colorPalette } from '@/styles/color-palette';
+import { FetchError } from '@/api/fetcher';
+
+interface CaptchaProps {
+ setCaptchaToken: (token: string) => void;
+ error?: unknown;
+}
+
+export function Captcha({ setCaptchaToken, error }: CaptchaProps) {
+ const captchaRef = useRef(null);
+
+ useEffect(() => {
+ if (error instanceof FetchError) {
+ captchaRef.current?.resetCaptcha();
+ }
+ }, [error]);
+
+ return (
+
+ );
+}
+
+interface FormCaptchaProps {
+ name: string;
+ error?: unknown;
+}
+
+export function FormCaptcha({ name, error }: FormCaptchaProps) {
+ const { setValue, formState } = useFormContext>();
+
+ function setCaptchaToken(token: string) {
+ setValue(name, token);
+ }
+
+ useEffect(() => {
+ if (error instanceof FetchError) {
+ setValue(name, '');
+ }
+ }, [error, name, setValue]);
+
+ return (
+
+
+
+ {formState.errors[name]?.message}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/layout/drawer-menu-items/drawer-menu-items-operator.tsx b/packages/apps/human-app/frontend/src/components/layout/drawer-menu-items/drawer-menu-items-operator.tsx
new file mode 100644
index 0000000000..1f845e0869
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/drawer-menu-items/drawer-menu-items-operator.tsx
@@ -0,0 +1,25 @@
+import { t } from 'i18next';
+import type { BottomMenuItem } from '@/components/layout/protected/drawer-navigation';
+import { HelpIcon, UserOutlinedIcon } from '@/components/ui/icons';
+import { routerPaths } from '@/router/router-paths';
+
+export const operatorDrawerBottomMenuItems: BottomMenuItem[] = [
+ {
+ label: t('components.DrawerNavigation.profile'),
+ link: routerPaths.operator.profile,
+ icon: ,
+ },
+ {
+ label: t('components.DrawerNavigation.help'),
+ icon: ,
+ onClick: () => {
+ // @ts-expect-error -- ...
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ...
+ if ($zoho?.salesiq?.chat?.start) {
+ // @ts-expect-error -- ...
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call -- ...
+ $zoho.salesiq.chat.start();
+ }
+ },
+ },
+];
diff --git a/packages/apps/human-app/frontend/src/components/layout/drawer-menu-items/drawer-menu-items-worker.tsx b/packages/apps/human-app/frontend/src/components/layout/drawer-menu-items/drawer-menu-items-worker.tsx
new file mode 100644
index 0000000000..b7eff4ce7c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/drawer-menu-items/drawer-menu-items-worker.tsx
@@ -0,0 +1,61 @@
+import Typography from '@mui/material/Typography';
+import { t } from 'i18next';
+import Grid from '@mui/material/Grid';
+import type {
+ BottomMenuItem,
+ TopMenuItem,
+} from '@/components/layout/protected/drawer-navigation';
+import { HelpIcon, UserOutlinedIcon, WorkIcon } from '@/components/ui/icons';
+import { routerPaths } from '@/router/router-paths';
+
+export const workerDrawerTopMenuItems = (
+ addressRegistered: boolean
+): TopMenuItem[] => {
+ return [
+
+
+
+ {t('components.DrawerNavigation.jobs')}
+
+ ,
+ {
+ label: t('components.DrawerNavigation.captchaLabelling'),
+ link: routerPaths.worker.enableLabeler,
+ disabled: !addressRegistered,
+ },
+ {
+ label: t('components.DrawerNavigation.jobsDiscovery'),
+ link: routerPaths.worker.jobsDiscovery,
+ disabled: !addressRegistered,
+ },
+ ];
+};
+
+export const workerDrawerBottomMenuItems: BottomMenuItem[] = [
+ {
+ label: t('components.DrawerNavigation.profile'),
+ link: routerPaths.worker.profile,
+ icon: ,
+ },
+ {
+ label: t('components.DrawerNavigation.help'),
+ icon: ,
+ onClick: () => {
+ // @ts-expect-error -- ...
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access -- ...
+ if ($zoho?.salesiq?.chat?.start) {
+ // @ts-expect-error -- ...
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call -- ...
+ $zoho.salesiq.chat.start();
+ }
+ },
+ },
+];
diff --git a/packages/apps/human-app/frontend/src/components/layout/footer.tsx b/packages/apps/human-app/frontend/src/components/layout/footer.tsx
new file mode 100644
index 0000000000..b7c96515a8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/footer.tsx
@@ -0,0 +1,123 @@
+import { Grid, Link, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { colorPalette } from '@/styles/color-palette';
+import { env } from '@/shared/env';
+import { Chat } from '@/pages/homepage/components/chat';
+import { breakpoints } from '@/styles/theme';
+
+interface FooterProps {
+ displayChatIcon?: boolean;
+ isProtected?: boolean;
+}
+export function Footer({ isProtected, displayChatIcon = true }: FooterProps) {
+ const { t } = useTranslation();
+ const isMobile = useIsMobile('md');
+
+ const parseLeftPadding = () => {
+ if (isMobile) {
+ return '0';
+ }
+ if (isProtected) {
+ return '200px';
+ }
+ return '44px';
+ };
+
+ return (
+
+
+
+
+
+ {t('components.footer.privacyPolicy')}
+
+
+
+
+ {t('components.footer.termsOfService')}
+
+
+
+
+ {t('components.footer.humanProtocol')}
+
+
+ {isMobile ? (
+
+ {t('components.footer.copyrightNote')}
+
+ ) : null}
+
+ {!isMobile ? (
+
+ {t('components.footer.copyrightNote')}
+
+ ) : null}
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/layout/protected/drawer-navigation.tsx b/packages/apps/human-app/frontend/src/components/layout/protected/drawer-navigation.tsx
new file mode 100644
index 0000000000..44235ed439
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/protected/drawer-navigation.tsx
@@ -0,0 +1,221 @@
+import Box from '@mui/material/Box';
+import Drawer from '@mui/material/Drawer';
+import CssBaseline from '@mui/material/CssBaseline';
+import List from '@mui/material/List';
+import ListItem from '@mui/material/ListItem';
+import ListItemButton from '@mui/material/ListItemButton';
+import ListItemText from '@mui/material/ListItemText';
+import { Stack, Typography } from '@mui/material';
+import { useNavigate } from 'react-router-dom';
+import { t } from 'i18next';
+import type { Dispatch, SetStateAction } from 'react';
+import { HumanLogoNavbarIcon } from '@/components/ui/icons';
+import { Button } from '@/components/ui/button';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { paddingX } from '@/components/layout/protected/navbar';
+
+const drawerWidth = 240;
+
+export interface DrawerItem {
+ label: string;
+ link?: string;
+ href?: string;
+ icon?: JSX.Element;
+ disabled?: boolean;
+ onClick?: () => void;
+}
+
+export type TopMenuItem = DrawerItem | JSX.Element;
+export type BottomMenuItem = DrawerItem;
+interface DrawerNavigationProps {
+ open: boolean;
+ setDrawerOpen: Dispatch>;
+ topMenuItems?: TopMenuItem[];
+ bottomMenuItems?: BottomMenuItem[];
+ signOut: () => void;
+}
+
+export function DrawerNavigation({
+ open,
+ setDrawerOpen,
+ topMenuItems,
+ bottomMenuItems,
+ signOut,
+}: DrawerNavigationProps) {
+ const navigate = useNavigate();
+ const isMobile = useIsMobile();
+
+ return (
+
+
+
+ {!isMobile && (
+
+
+
+ )}
+
+
+ {topMenuItems?.map((item, index) => {
+ if (!('label' in item)) {
+ return (
+
+
+ {item}
+
+
+ );
+ }
+
+ const { link, label, disabled, href, onClick } = item;
+ return (
+
+ {
+ if (onClick) {
+ onClick();
+ return;
+ }
+ if (disabled) return;
+ if (isMobile) setDrawerOpen(false);
+ if (href) {
+ const element = document.createElement('a');
+ element.href = href;
+ element.target = '_blank';
+ document.body.appendChild(element);
+ element.click();
+ return;
+ }
+ if (link && !href) {
+ navigate(link);
+ }
+ }}
+ >
+
+
+ {label}
+
+ }
+ sx={{
+ marginLeft: index === 0 ? '10px' : '0px',
+ }}
+ />
+
+
+
+ );
+ })}
+
+
+ {bottomMenuItems?.map(({ label, link, icon, href, onClick }) => (
+
+ {
+ if (onClick) {
+ onClick();
+ return;
+ }
+ if (isMobile) setDrawerOpen(false);
+ if (href) {
+ const element = document.createElement('a');
+ element.href = href;
+ element.target = '_blank';
+ document.body.appendChild(element);
+ element.click();
+ return;
+ }
+ if (link && !href) {
+ navigate(link);
+ }
+ }}
+ >
+
+ {icon}
+
+ {label}
+
+ }
+ sx={{
+ textAlign: 'center',
+ marginLeft: '10px',
+ }}
+ />
+
+
+
+ ))}
+
+
+ {
+ if (isMobile) setDrawerOpen(false);
+ signOut();
+ }}
+ size="large"
+ sx={{
+ marginBottom: '44px',
+ mx: isMobile ? '28px' : '16px',
+ }}
+ variant="outlined"
+ >
+ {t('components.DrawerNavigation.logout')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/layout/protected/layout-notification-context.tsx b/packages/apps/human-app/frontend/src/components/layout/protected/layout-notification-context.tsx
new file mode 100644
index 0000000000..57c765b9d8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/protected/layout-notification-context.tsx
@@ -0,0 +1,14 @@
+import { createContext } from 'react';
+import type { TopNotificationType } from '@/components/ui/top-notification';
+
+export interface TopNotificationPayload {
+ content: string;
+ type: TopNotificationType;
+}
+
+export type SetTopNotificationFn = (data: TopNotificationPayload) => void;
+
+export const ProtectedLayoutContext = createContext<{
+ setTopNotification: SetTopNotificationFn;
+ closeNotification: () => void;
+} | null>(null);
diff --git a/packages/apps/human-app/frontend/src/components/layout/protected/layout.tsx b/packages/apps/human-app/frontend/src/components/layout/protected/layout.tsx
new file mode 100644
index 0000000000..e7ba58c860
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/protected/layout.tsx
@@ -0,0 +1,217 @@
+import { Grid } from '@mui/material';
+import type { Dispatch, SetStateAction } from 'react';
+import { useEffect, useRef, useState } from 'react';
+import { styled } from '@mui/material/styles';
+import { Outlet } from 'react-router-dom';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { useBackgroundColorStore } from '@/hooks/use-background-store';
+import type { PageHeaderProps } from '@/components/layout/protected/page-header';
+import { PageHeader } from '@/components/layout/protected/page-header';
+import { breakpoints } from '@/styles/theme';
+import { TopNotification } from '@/components/ui/top-notification';
+import type { TopNotificationPayload } from '@/components/layout/protected/layout-notification-context';
+import { ProtectedLayoutContext } from '@/components/layout/protected/layout-notification-context';
+import { useIsHCaptchaLabelingPage } from '@/hooks/use-is-hcaptcha-labeling-page';
+import { Footer } from '../footer';
+import { Navbar } from './navbar';
+
+const Main = styled('main', {
+ shouldForwardProp: (prop) => prop !== 'open' && prop !== 'isMobile',
+})<{
+ open?: boolean;
+ isMobile?: boolean;
+}>(({ theme, open, isMobile }) => ({
+ width: '100%',
+ display: 'flex',
+ flex: '1',
+ transition: theme.transitions.create('margin', {
+ easing: theme.transitions.easing.sharp,
+ duration: theme.transitions.duration.leavingScreen,
+ }),
+ ...(open && {
+ transition: theme.transitions.create('margin', {
+ easing: theme.transitions.easing.easeOut,
+ duration: theme.transitions.duration.enteringScreen,
+ }),
+ paddingLeft: isMobile ? 0 : `140px`,
+ }),
+}));
+
+export function Layout({
+ pageHeaderProps,
+ renderDrawer,
+ renderHCaptchaStatisticsDrawer,
+}: {
+ pageHeaderProps: PageHeaderProps;
+ renderDrawer: (
+ open: boolean,
+ setDrawerOpen: Dispatch>
+ ) => JSX.Element;
+ renderHCaptchaStatisticsDrawer?: (isOpen: boolean) => JSX.Element;
+}) {
+ const [notificationWith, setNotificationWith] = useState<
+ number | undefined
+ >();
+ const layoutElementRef = useRef();
+ const isHCaptchaLabelingPage = useIsHCaptchaLabelingPage();
+ const [notification, setNotification] =
+ useState(null);
+ const isMobile = useIsMobile();
+ const [drawerOpen, setDrawerOpen] = useState(!isMobile);
+ const [hcaptchaDrawerOpen, setHcaptchaDrawerOpen] = useState(false);
+ const { backgroundColor } = useBackgroundColorStore();
+ const toggleUserStatsDrawer = isHCaptchaLabelingPage
+ ? () => {
+ setHcaptchaDrawerOpen((state) => !state);
+ }
+ : undefined;
+
+ useEffect(() => {
+ if (isMobile) {
+ setHcaptchaDrawerOpen(false);
+ setDrawerOpen(false);
+ } else {
+ setHcaptchaDrawerOpen(false);
+ setDrawerOpen(true);
+ }
+ }, [isMobile]);
+
+ const setNotificationWidth = () => {
+ if (layoutElementRef.current) {
+ setNotificationWith(layoutElementRef.current.clientWidth);
+ }
+ };
+ useEffect(() => {
+ setNotificationWidth();
+ window.addEventListener('resize', () => {
+ setNotificationWidth();
+ });
+ return () => {
+ window.removeEventListener('resize', setNotificationWidth);
+ };
+ }, []);
+
+ useEffect(() => {
+ setNotificationWidth();
+ }, [notification]);
+
+ return (
+ {
+ setNotification(data);
+ },
+ closeNotification: () => {
+ setNotification(null);
+ },
+ }}
+ >
+
+
+ {renderDrawer(drawerOpen, setDrawerOpen)}
+ {isHCaptchaLabelingPage && renderHCaptchaStatisticsDrawer
+ ? renderHCaptchaStatisticsDrawer(hcaptchaDrawerOpen)
+ : null}
+
+
+
+
+ {notification ? (
+
+ {
+ setNotification(null);
+ }}
+ type={notification.type}
+ >
+ {notification.content}
+
+
+ ) : null}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/layout/protected/navbar.tsx b/packages/apps/human-app/frontend/src/components/layout/protected/navbar.tsx
new file mode 100644
index 0000000000..ec5eedbb73
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/protected/navbar.tsx
@@ -0,0 +1,100 @@
+import { Grid, IconButton, Stack } from '@mui/material';
+import MenuIcon from '@mui/icons-material/Menu';
+import CloseIcon from '@mui/icons-material/Close';
+import { t } from 'i18next';
+import { HumanLogoIcon } from '@/components/ui/icons';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { colorPalette } from '@/styles/color-palette';
+import { Button } from '@/components/ui/button';
+import { useIsHCaptchaLabelingPage } from '@/hooks/use-is-hcaptcha-labeling-page';
+
+export const paddingX = '44px';
+
+interface NavbarProps {
+ open: boolean;
+ setOpen: (open: boolean) => void;
+ toggleUserStatsDrawer?: () => void;
+ userStatsDrawerOpen: boolean;
+}
+
+export function Navbar({
+ setOpen,
+ open,
+ userStatsDrawerOpen,
+ toggleUserStatsDrawer,
+}: NavbarProps) {
+ const isMobile = useIsMobile();
+ const isHCaptchaLabelingPage = useIsHCaptchaLabelingPage();
+ const getIcon = () => {
+ switch (true) {
+ case open:
+ return (
+ {
+ setOpen(false);
+ }}
+ />
+ );
+ case !open && !userStatsDrawerOpen:
+ return (
+ {
+ setOpen(true);
+ }}
+ />
+ );
+ case userStatsDrawerOpen:
+ return (
+ {
+ if (toggleUserStatsDrawer) {
+ toggleUserStatsDrawer();
+ }
+ }}
+ />
+ );
+ default:
+ return null;
+ }
+ };
+
+ return (
+
+
+
+ {isHCaptchaLabelingPage && toggleUserStatsDrawer ? (
+
+ {t('translation:worker.hcaptchaLabelingStats.statistics')}
+
+ ) : null}
+ {getIcon()}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/layout/protected/page-header.tsx b/packages/apps/human-app/frontend/src/components/layout/protected/page-header.tsx
new file mode 100644
index 0000000000..fb169f0c76
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/protected/page-header.tsx
@@ -0,0 +1,68 @@
+import { Grid, Typography } from '@mui/material';
+import React from 'react';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { breakpoints } from '@/styles/theme';
+
+export interface PageHeaderProps {
+ headerIcon: React.ReactNode;
+ headerText: string;
+ headerItem?: React.ReactNode;
+}
+
+export function PageHeader({
+ headerIcon,
+ headerText,
+ headerItem,
+}: PageHeaderProps) {
+ const isMobile = useIsMobile();
+ return (
+
+
+
+
+
+ {headerIcon}
+
+
+
+
+ {headerText}
+
+
+
+
+ {!isMobile ? {headerItem} : null}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/layout/unprotected/layout.tsx b/packages/apps/human-app/frontend/src/components/layout/unprotected/layout.tsx
new file mode 100644
index 0000000000..f156f86679
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/unprotected/layout.tsx
@@ -0,0 +1,49 @@
+import { Container, Grid } from '@mui/material';
+import { Outlet } from 'react-router-dom';
+import { useBackgroundColorStore } from '@/hooks/use-background-store';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { colorPalette } from '@/styles/color-palette';
+import { Footer } from '../footer';
+import { Navbar } from './navbar';
+
+interface LayoutProps {
+ withNavigation?: boolean;
+}
+
+export function Layout({ withNavigation = true }: LayoutProps) {
+ const { backgroundColor } = useBackgroundColorStore();
+ const isMobile = useIsMobile();
+
+ return (
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/layout/unprotected/navbar.tsx b/packages/apps/human-app/frontend/src/components/layout/unprotected/navbar.tsx
new file mode 100644
index 0000000000..34464dbc93
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/layout/unprotected/navbar.tsx
@@ -0,0 +1,111 @@
+import { useState } from 'react';
+import { Box, Drawer, IconButton } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import MenuIcon from '@mui/icons-material/Menu';
+import { Link, useLocation } from 'react-router-dom';
+import { HumanLogoIcon, HumanLogoNavbarIcon } from '@/components/ui/icons';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { Button } from '@/components/ui/button';
+import { breakpoints } from '@/styles/theme';
+import { routerPaths } from '@/router/router-paths';
+import { env } from '@/shared/env';
+
+interface NavbarProps {
+ withNavigation: boolean;
+}
+
+export function Navbar({ withNavigation }: NavbarProps) {
+ const { t } = useTranslation();
+ const [isDrawerOpen, setIsDrawerOpen] = useState(false);
+ const isMobile = useIsMobile();
+ const location = useLocation();
+ const isMainPage = location.pathname === routerPaths.homePage;
+ return (
+
+ {isMobile ? : }
+ {withNavigation ? (
+
+
+ {isMainPage ? (
+ <>
+
+ {t('components.navbar.humanProtocol')}
+
+
+ {t('components.navbar.howItWorks')}
+
+ >
+ ) : null}
+
+
+ {
+ setIsDrawerOpen(!isDrawerOpen);
+ }}
+ >
+
+
+ {
+ setIsDrawerOpen(false);
+ }}
+ open={isDrawerOpen}
+ >
+
+
+ {t('components.navbar.humanProtocol')}
+
+
+ {t('components.navbar.howItWorks')}
+
+
+
+
+
+ ) : null}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/alert.tsx b/packages/apps/human-app/frontend/src/components/ui/alert.tsx
new file mode 100644
index 0000000000..6b8bb48e89
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/alert.tsx
@@ -0,0 +1,35 @@
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import WarningIcon from '@mui/icons-material/Warning';
+import ErrorIcon from '@mui/icons-material/Error';
+import MuiAlert from '@mui/material/Alert';
+import type { AlertProps as MuiAlertProps } from '@mui/material/Alert';
+import { Typography } from '@mui/material';
+import { colorPalette } from '@/styles/color-palette';
+
+const getIcon = (severity: MuiAlertProps['severity']) => {
+ switch (severity) {
+ case 'success':
+ return ;
+
+ case 'error':
+ return ;
+
+ case 'warning':
+ return ;
+
+ default:
+ return undefined;
+ }
+};
+
+export function Alert({ severity, color, children, ...rest }: MuiAlertProps) {
+ const icon = getIcon(severity);
+ const fontColor = color === 'error' ? colorPalette.error.main : 'inherit';
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/button.tsx b/packages/apps/human-app/frontend/src/components/ui/button.tsx
new file mode 100644
index 0000000000..fbe345c598
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/button.tsx
@@ -0,0 +1,23 @@
+import type { Link, LinkProps } from 'react-router-dom';
+import { forwardRef } from 'react';
+import MuiButton from '@mui/material/Button';
+import type { ButtonProps } from '@mui/material/Button';
+import CircularProgress from '@mui/material/CircularProgress';
+
+export type CustomButtonProps = ButtonProps &
+ Partial & {
+ component?: typeof Link;
+ loading?: boolean;
+ };
+
+export const Button = forwardRef(
+ ({ children, loading, disabled, ...props }, ref) => {
+ return (
+
+ <>{loading ? : children}>
+
+ );
+ }
+);
+
+Button.displayName = 'Button';
diff --git a/packages/apps/human-app/frontend/src/components/ui/chip.tsx b/packages/apps/human-app/frontend/src/components/ui/chip.tsx
new file mode 100644
index 0000000000..1d2b40d3ce
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/chip.tsx
@@ -0,0 +1,33 @@
+import { Box, Typography } from '@mui/material';
+import { colorPalette } from '@/styles/color-palette';
+
+interface ChipProps {
+ label: string;
+ key?: string;
+ backgroundColor?: string;
+}
+export function Chip({ label, backgroundColor }: ChipProps) {
+ return (
+
+
+ {label}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/chips.tsx b/packages/apps/human-app/frontend/src/components/ui/chips.tsx
new file mode 100644
index 0000000000..388a4d9018
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/chips.tsx
@@ -0,0 +1,16 @@
+import { Grid } from '@mui/material';
+import { Chip } from '@/components/ui/chip';
+
+interface ChipsProps {
+ data: string[];
+}
+
+export function Chips({ data }: ChipsProps) {
+ return (
+
+ {data.map((chipLabel) => (
+
+ ))}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/connect-wallet-btn.tsx b/packages/apps/human-app/frontend/src/components/ui/connect-wallet-btn.tsx
new file mode 100644
index 0000000000..f224aec805
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/connect-wallet-btn.tsx
@@ -0,0 +1,25 @@
+import { useTranslation } from 'react-i18next';
+import type { CustomButtonProps } from '@/components/ui/button';
+import { Button } from '@/components/ui/button';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+
+export function ConnectWalletBtn(props: CustomButtonProps) {
+ const { openModal, isConnected } = useWalletConnect();
+ const { t } = useTranslation();
+ const defaultStatus = isConnected
+ ? t('components.wallet.connectBtn.disconnect')
+ : t('components.wallet.connectBtn.connect');
+ const btnContent = props.children ? props.children : defaultStatus;
+
+ return (
+ {
+ return void openModal();
+ }}
+ variant="contained"
+ >
+ {btnContent}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/counter.tsx b/packages/apps/human-app/frontend/src/components/ui/counter.tsx
new file mode 100644
index 0000000000..800b90c836
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/counter.tsx
@@ -0,0 +1,27 @@
+import { useCountDown } from '@/hooks/use-count-down';
+import { padZero } from '@/shared/helpers/counter-helpers';
+
+export function Counter({
+ date,
+ onFinish,
+}: {
+ date: string;
+ onFinish?: () => void;
+}) {
+ const time = useCountDown(new Date(date).getTime() - Date.now(), onFinish);
+ if (!time) {
+ return null;
+ }
+
+ if (!time.days && !time.hours && !time.minutes) {
+ return `00:${padZero(time.seconds)}`;
+ }
+ if (!time.days && !time.hours) {
+ return `${padZero(time.minutes)}:${padZero(time.seconds)}`;
+ }
+ if (!time.days) {
+ return `${padZero(time.hours)}:${padZero(time.minutes)}:${padZero(time.seconds)}`;
+ }
+
+ return `${time.days}:${padZero(time.hours)}:${padZero(time.minutes)}:${padZero(time.seconds)}`;
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/empty-placeholder.tsx b/packages/apps/human-app/frontend/src/components/ui/empty-placeholder.tsx
new file mode 100644
index 0000000000..38f4d0b5b9
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/empty-placeholder.tsx
@@ -0,0 +1,11 @@
+import Typography from '@mui/material/Typography';
+import { t } from 'i18next';
+import { colorPalette } from '@/styles/color-palette';
+
+export function EmptyPlaceholder() {
+ return (
+
+ {t('operator.addKeysPage.existingKeys.noValue')}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/icons.tsx b/packages/apps/human-app/frontend/src/components/ui/icons.tsx
new file mode 100644
index 0000000000..284fdd7355
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/icons.tsx
@@ -0,0 +1,53 @@
+import HomepageLogoIcon from '@/assets/icons/icons-homepage/logo.svg';
+import HomepageUserIcon from '@/assets/icons/icons-homepage/user.svg';
+import HomepageWorkIcon from '@/assets/icons/icons-homepage/work.svg';
+import HumanLogoIcon from '@/assets/icons/icons-human-logo/human-logo.svg';
+import HumanLogoCircleIcon from '@/assets/icons/icons-human-logo/human-logo-circle.svg';
+import BackArrowIcon from '@/assets/icons/back-arrow.svg';
+import ChatIcon from '@/assets/icons/chat.svg';
+import HandIcon from '@/assets/icons/hand.svg';
+import InfoIcon from '@/assets/icons/info.svg';
+import RefreshIcon from '@/assets/icons/refresh.svg';
+import UserFilledIcon from '@/assets/icons/user-filled.svg';
+import UserOutlinedIcon from '@/assets/icons/user-outlined.svg';
+import UserSecondaryIcon from '@/assets/icons/user-secondary.svg';
+import WorkIcon from '@/assets/icons/work.svg';
+import WorkSecondaryIcon from '@/assets/icons/work-secondary.svg';
+import HumanLogoNavbarIcon from '@/assets/icons/icons-navbar/human-logo-navbar.svg';
+import DiscordIcon from '@/assets/icons/icons-homepage/discord.svg';
+import HelpIcon from '@/assets/icons/help.svg';
+import MobileHeaderIcon from '@/assets/icons/icons-homepage/mobile-header.svg';
+import ProfileIcon from '@/assets/icons/profile-icon.svg';
+import CheckmarkIcon from '@/assets/icons/checkmark-icon.svg';
+import LockerIcon from '@/assets/icons/locker-icon.svg';
+import FiltersButtonIcon from '@/assets/icons/filters-button-icon.svg';
+import SortArrow from '@/assets/icons/sort-arrow.svg';
+import FilersIcon from '@/assets/icons/filters-icon.svg';
+
+export {
+ HomepageLogoIcon,
+ HomepageUserIcon,
+ HomepageWorkIcon,
+ HumanLogoIcon,
+ HumanLogoCircleIcon,
+ HumanLogoNavbarIcon,
+ BackArrowIcon,
+ ChatIcon,
+ HandIcon,
+ InfoIcon,
+ RefreshIcon,
+ UserFilledIcon,
+ UserOutlinedIcon,
+ UserSecondaryIcon,
+ WorkIcon,
+ WorkSecondaryIcon,
+ DiscordIcon,
+ HelpIcon,
+ MobileHeaderIcon,
+ ProfileIcon,
+ CheckmarkIcon,
+ LockerIcon,
+ FiltersButtonIcon,
+ SortArrow,
+ FilersIcon,
+};
diff --git a/packages/apps/human-app/frontend/src/components/ui/list-item.tsx b/packages/apps/human-app/frontend/src/components/ui/list-item.tsx
new file mode 100644
index 0000000000..b712caf2a8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/list-item.tsx
@@ -0,0 +1,24 @@
+import { Typography, ListItem as MuiListItem } from '@mui/material';
+
+export function ListItem({
+ children,
+ label,
+}: {
+ children: React.ReactElement;
+ label: string;
+}) {
+ return (
+
+ {label}
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/loader.tsx b/packages/apps/human-app/frontend/src/components/ui/loader.tsx
new file mode 100644
index 0000000000..7e8eaf4581
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/loader.tsx
@@ -0,0 +1,12 @@
+import { styled } from '@mui/material';
+import type { CircularProgressProps } from '@mui/material';
+import CircularProgress from '@mui/material/CircularProgress';
+import { colorPalette } from '@/styles/color-palette';
+
+const LoaderStyled = styled(CircularProgress)({
+ '.MuiCircularProgress-circle': { color: colorPalette.primary.main },
+});
+
+export function Loader({ ...props }: CircularProgressProps) {
+ return ;
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/modal/display-modal.tsx b/packages/apps/human-app/frontend/src/components/ui/modal/display-modal.tsx
new file mode 100644
index 0000000000..b42b3ba5d6
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/modal/display-modal.tsx
@@ -0,0 +1,18 @@
+import { ModalContent } from './modal-content';
+import { useModalStore } from './modal.store';
+import { Modal } from './modal';
+import { ModalHeader } from './modal-header';
+
+export function DisplayModal() {
+ const { isModalOpen, closeModal, modalState } = useModalStore();
+ return (
+ <>
+ {modalState ? (
+
+
+
+
+ ) : null}
+ >
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/modal/modal-content.tsx b/packages/apps/human-app/frontend/src/components/ui/modal/modal-content.tsx
new file mode 100644
index 0000000000..b6083593e1
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/modal/modal-content.tsx
@@ -0,0 +1,18 @@
+import type { ComponentType } from 'react';
+import { ModalExample } from '@/pages/playground/modal-example/modal-example';
+import { WalletConnectModal } from '@/auth-web3/wallet-connect-modal';
+import type { ModalStateKeys, ModalStateUnion } from './modal.store';
+import { MODAL_STATE } from './modal.store';
+
+const MODAL_COMPONENTS: Record = {
+ [MODAL_STATE.MODAL_EXAMPLE]: ModalExample,
+ [MODAL_STATE.WALLET_CONNECT]: WalletConnectModal,
+};
+
+interface ModalContent {
+ modalType: ModalStateUnion;
+}
+export function ModalContent({ modalType }: ModalContent) {
+ const Content = MODAL_COMPONENTS[modalType];
+ return ;
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/modal/modal-header.test.tsx b/packages/apps/human-app/frontend/src/components/ui/modal/modal-header.test.tsx
new file mode 100644
index 0000000000..521cbbdaea
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/modal/modal-header.test.tsx
@@ -0,0 +1,48 @@
+import { describe, expect, vi } from 'vitest';
+import { fireEvent } from '@testing-library/react';
+import { renderWithWrapper } from '@/shared/test-utils/render-with-wrapper';
+import { ModalHeader } from '@/components/ui/modal/modal-header';
+
+const mockedCloseProcessModal = vi.fn();
+
+const closeButtonProps = {
+ closeButton: {
+ isVisible: true,
+ onClick: mockedCloseProcessModal,
+ },
+};
+
+describe('Modal header', () => {
+ it('is close button visible', () => {
+ const { getByTestId } = renderWithWrapper(
+
+ );
+ const closeButton = getByTestId('button-close-modal');
+ expect(closeButton).toBeVisible();
+ });
+
+ it('is close button not visible', () => {
+ const { queryByTestId } = renderWithWrapper( );
+ const closeModal = queryByTestId('button-close-modal');
+ expect(closeModal).toBeNull();
+ });
+
+ it('is breadcrumb not visible', () => {
+ const { queryByTestId } = renderWithWrapper( );
+ const breadcrumb = queryByTestId('breadcrumb-button');
+ expect(breadcrumb).toBeNull();
+ });
+
+ it('close modal', () => {
+ //ARRANGE
+ const { getByTestId } = renderWithWrapper(
+
+ );
+ //ACT
+ const button = getByTestId('button-close-modal');
+ expect(button).toBeVisible();
+ //EXPECT
+ fireEvent.click(button);
+ expect(mockedCloseProcessModal).toBeCalledTimes(1);
+ });
+});
diff --git a/packages/apps/human-app/frontend/src/components/ui/modal/modal-header.tsx b/packages/apps/human-app/frontend/src/components/ui/modal/modal-header.tsx
new file mode 100644
index 0000000000..e81aed17da
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/modal/modal-header.tsx
@@ -0,0 +1,36 @@
+import Grid from '@mui/material/Grid';
+import Button from '@mui/material/Button';
+import { Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+
+interface ModalHeaderElementProps {
+ isVisible: boolean;
+ onClick: () => void;
+}
+
+interface ModalHeaderProps {
+ closeButton?: ModalHeaderElementProps;
+}
+
+export function ModalHeader({ closeButton }: ModalHeaderProps) {
+ const { t } = useTranslation();
+ return (
+
+
+ {closeButton ? (
+
+
+
+ {t('components.modal.header.closeBtn')}
+
+
+
+ ) : null}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/modal/modal.store.ts b/packages/apps/human-app/frontend/src/components/ui/modal/modal.store.ts
new file mode 100644
index 0000000000..e34e16f275
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/modal/modal.store.ts
@@ -0,0 +1,34 @@
+import { create } from 'zustand';
+import type { ReactNode } from 'react';
+
+interface ModalState {
+ isModalOpen: boolean;
+ modalState: ModalStateUnion | undefined;
+ openModal: (
+ modalState: ModalStateUnion,
+ additionalContent?: ReactNode
+ ) => void;
+ closeModal: () => void;
+ additionalContent: ReactNode;
+}
+
+export const MODAL_STATE = {
+ MODAL_EXAMPLE: 'MODAL_EXAMPLE',
+ WALLET_CONNECT: 'WALLET_CONNECT',
+} as const;
+
+export type ModalStateUnion = (typeof MODAL_STATE)[keyof typeof MODAL_STATE];
+
+export type ModalStateKeys = keyof typeof MODAL_STATE;
+
+export const useModalStore = create((set) => ({
+ isModalOpen: false,
+ modalState: undefined,
+ additionalContent: undefined,
+ openModal: (modalState, additionalContent) => {
+ set(() => ({ isModalOpen: true, modalState, additionalContent }));
+ },
+ closeModal: () => {
+ set(() => ({ isModalOpen: false, modalState: undefined }));
+ },
+}));
diff --git a/packages/apps/human-app/frontend/src/components/ui/modal/modal.tsx b/packages/apps/human-app/frontend/src/components/ui/modal/modal.tsx
new file mode 100644
index 0000000000..573d765da1
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/modal/modal.tsx
@@ -0,0 +1,22 @@
+import DialogMui from '@mui/material/Dialog';
+import type { DialogProps as DialogMuiProps } from '@mui/material/Dialog';
+import { DialogContent } from '@mui/material';
+
+interface ModalProps extends Omit {
+ isOpen: boolean;
+}
+
+export function Modal({ children, isOpen, ...rest }: ModalProps) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/optional-text.tsx b/packages/apps/human-app/frontend/src/components/ui/optional-text.tsx
new file mode 100644
index 0000000000..dc96ed7045
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/optional-text.tsx
@@ -0,0 +1,14 @@
+import Grid from '@mui/material/Grid';
+import { EmptyPlaceholder } from '@/components/ui/empty-placeholder';
+
+export function OptionalText({ text }: { text?: string }) {
+ if (!text) {
+ return ;
+ }
+
+ return (
+
+ {text}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/page-card.tsx b/packages/apps/human-app/frontend/src/components/ui/page-card.tsx
new file mode 100644
index 0000000000..9e4bca01ea
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/page-card.tsx
@@ -0,0 +1,298 @@
+import type { SxProps, Theme } from '@mui/material';
+import { Grid, Typography, styled } from '@mui/material';
+import ArrowBackIcon from '@mui/icons-material/ArrowBack';
+import { useNavigate } from 'react-router-dom';
+import { useEffect } from 'react';
+import { t } from 'i18next';
+import { Button } from '@/components/ui/button';
+import { breakpoints } from '@/styles/theme';
+import { routerPaths } from '@/router/router-paths';
+import { colorPalette } from '@/styles/color-palette';
+import { useBackgroundColorStore } from '@/hooks/use-background-store';
+import { Loader } from '@/components/ui/loader';
+import { Alert } from '@/components/ui/alert';
+
+const IconWrapper = styled('div')(() => ({
+ width: '40px',
+ height: '40px',
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderRadius: '50%',
+ backgroundColor: colorPalette.paper.main,
+ cursor: 'pointer',
+ ':hover': {
+ cursor: 'pointer',
+ },
+ fontSize: '26px',
+}));
+
+const commonStyles: SxProps = {
+ padding: '2rem 2rem 6rem 2rem',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderRadius: '20px',
+ minHeight: '70vh',
+ maxWidth: '1200px',
+ width: '100%',
+ background: colorPalette.white,
+};
+
+interface FormCardProps {
+ children: React.JSX.Element;
+ title?: React.JSX.Element | string;
+ alert?: React.JSX.Element;
+ childrenMaxWidth?: string;
+ backArrowPath?: string | -1;
+ cancelRouterPathOrCallback?: string | -1 | (() => void);
+ hiddenCancelButton?: boolean;
+ withLayoutBackground?: boolean;
+ loader?: boolean;
+}
+
+export function PageCard({
+ children,
+ title,
+ alert,
+ childrenMaxWidth = '486px',
+ backArrowPath = -1,
+ cancelRouterPathOrCallback = routerPaths.homePage,
+ withLayoutBackground = true,
+ hiddenCancelButton = false,
+}: FormCardProps) {
+ const { setGrayBackground } = useBackgroundColorStore();
+ const navigate = useNavigate();
+
+ useEffect(() => {
+ if (withLayoutBackground) {
+ setGrayBackground();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- call this effect once
+ }, []);
+
+ const goBack = (path: string | -1) => {
+ if (typeof path === 'string') {
+ navigate(path);
+ return;
+ }
+ navigate(path);
+ };
+
+ return (
+
+ {!hiddenCancelButton && (
+
+ {
+ if (cancelRouterPathOrCallback instanceof Function) {
+ cancelRouterPathOrCallback();
+ return;
+ }
+ goBack(cancelRouterPathOrCallback);
+ }}
+ >
+
+ {t('components.modal.header.closeBtn')}
+
+
+
+ )}
+
+
+
+ {backArrowPath ? (
+
+
+
+ ) : null}
+ {!hiddenCancelButton && (
+ {
+ if (cancelRouterPathOrCallback instanceof Function) {
+ cancelRouterPathOrCallback();
+ return;
+ }
+ goBack(cancelRouterPathOrCallback);
+ }}
+ >
+
+ {t('components.modal.header.closeBtn')}
+
+
+ )}
+
+
+
+ {alert ? <>{alert}> : null}
+
+
+ {backArrowPath ? (
+
+
+
+ ) : null}
+
+
+ {title}
+
+
+
+ {children}
+
+
+
+
+ );
+}
+
+export function PageCardLoader({
+ withLayoutBackground = true,
+ cardMaxWidth = '100%',
+}: {
+ cardMaxWidth?: string;
+ withLayoutBackground?: boolean;
+}) {
+ const { setGrayBackground } = useBackgroundColorStore();
+
+ useEffect(() => {
+ if (withLayoutBackground) {
+ setGrayBackground();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- call this effect once
+ }, []);
+ const sx = cardMaxWidth
+ ? { ...commonStyles, maxWidth: cardMaxWidth }
+ : commonStyles;
+
+ return (
+
+
+
+ );
+}
+export function PageCardError({
+ errorMessage,
+ children,
+ withLayoutBackground,
+ cardMaxWidth = '100%',
+}:
+ | {
+ errorMessage: string;
+ children?: never;
+ cardMaxWidth?: string;
+ withLayoutBackground?: boolean;
+ }
+ | {
+ errorMessage?: never;
+ children: React.ReactElement;
+ cardMaxWidth?: string;
+ withLayoutBackground?: boolean;
+ }) {
+ const navigate = useNavigate();
+ const { setGrayBackground } = useBackgroundColorStore();
+
+ const sx = cardMaxWidth
+ ? { ...commonStyles, maxWidth: cardMaxWidth }
+ : commonStyles;
+
+ useEffect(() => {
+ if (withLayoutBackground) {
+ setGrayBackground();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- call this effect once
+ }, []);
+
+ return (
+
+ {children ? (
+ children
+ ) : (
+ <>
+
+ {errorMessage}
+
+
+ {t('components.pageCardError.reload')}
+
+ {
+ navigate(routerPaths.homePage);
+ }}
+ variant="outlined"
+ >
+ {t('components.pageCardError.goHome')}
+
+ >
+ )}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/profile-list-item.tsx b/packages/apps/human-app/frontend/src/components/ui/profile-list-item.tsx
new file mode 100644
index 0000000000..ae600c069c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/profile-list-item.tsx
@@ -0,0 +1,92 @@
+import { ListItem, ListItemText, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { Button } from '@/components/ui/button';
+import { CheckmarkIcon, LockerIcon } from '@/components/ui/icons';
+import { colorPalette } from '@/styles/color-palette';
+import { Chips } from '@/components/ui/chips';
+
+interface ProfileListItemProps {
+ header: string;
+ paragraph: string | string[];
+ isStatusListItem?: boolean;
+}
+
+export function ProfileListItem({
+ header,
+ paragraph,
+ isStatusListItem,
+}: ProfileListItemProps) {
+ const { t } = useTranslation();
+
+ return (
+
+
+
+ {header}
+
+ {Array.isArray(paragraph) ? (
+
+ ) : (
+
+
+ {paragraph}
+
+ {isStatusListItem === true && (
+
+
+
+ )}
+ {isStatusListItem === false && (
+
+
+
+ )}
+
+ )}
+ {isStatusListItem === true && (
+
+ {t('operator.profile.about.status.statusDeactivateButton')}
+
+ )}
+ {isStatusListItem === false && (
+
+ {t('operator.profile.about.status.statusActivateButton')}
+
+ )}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/success-label.tsx b/packages/apps/human-app/frontend/src/components/ui/success-label.tsx
new file mode 100644
index 0000000000..2335ab5bb0
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/success-label.tsx
@@ -0,0 +1,15 @@
+import Grid from '@mui/material/Grid';
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import { colorPalette } from '@/styles/color-palette';
+
+export function SuccessLabel({ children }: { children: string }) {
+ return (
+
+ {children}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/table-button.tsx b/packages/apps/human-app/frontend/src/components/ui/table-button.tsx
new file mode 100644
index 0000000000..0cda2cb026
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/table-button.tsx
@@ -0,0 +1,28 @@
+import Typography from '@mui/material/Typography';
+import type { CustomButtonProps } from '@/components/ui/button';
+import { Button } from '@/components/ui/button';
+import { colorPalette } from '@/styles/color-palette';
+
+export function TableButton(props: CustomButtonProps) {
+ return (
+
+
+ {props.children}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/table/table-header-cell.tsx b/packages/apps/human-app/frontend/src/components/ui/table/table-header-cell.tsx
new file mode 100644
index 0000000000..3bcc251a2e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/table/table-header-cell.tsx
@@ -0,0 +1,77 @@
+/* eslint-disable jsx-a11y/click-events-have-key-events */
+/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
+import React, { forwardRef, useState } from 'react';
+import Popover from '@mui/material/Popover';
+import type { TableCellBaseProps } from '@mui/material/TableCell/TableCell';
+import type { IconType } from '@/pages/worker/jobs/components/text-header-with-icon';
+import { TextHeaderWithIcon } from '@/pages/worker/jobs/components/text-header-with-icon';
+
+type CommonProps = TableCellBaseProps & {
+ popoverContent: React.ReactElement;
+};
+
+type PropsWithIcon = CommonProps & {
+ headerText: string;
+ iconType: IconType;
+};
+type PropsWithoutIcon = CommonProps & {
+ headerText?: never;
+ iconType?: never;
+};
+
+type HeaderCellProps = PropsWithoutIcon | PropsWithIcon;
+
+export const TableHeaderCell = forwardRef<
+ HTMLTableDataCellElement,
+ HeaderCellProps
+>(function TableHeaderCell(
+ { popoverContent, headerText, iconType, ...rest },
+ ref
+) {
+ const [anchorEl, setAnchorEl] = useState(
+ null
+ );
+
+ const handleClick = (event: React.MouseEvent) => {
+ setAnchorEl(event.currentTarget);
+ };
+
+ const handleClose = () => {
+ setAnchorEl(null);
+ };
+
+ const open = Boolean(anchorEl);
+ const id = open ? 'simple-popover' : undefined;
+
+ const getHeader = () => {
+ if (!iconType) {
+ return ;
+ }
+ return (
+
+
+
+ );
+ };
+
+ return (
+ <>
+ {getHeader()}
+
+ {popoverContent}
+
+ >
+ );
+});
+
+TableHeaderCell.displayName = 'TableHeaderCell';
diff --git a/packages/apps/human-app/frontend/src/components/ui/table/table-header-menu.tsx/filtering.tsx b/packages/apps/human-app/frontend/src/components/ui/table/table-header-menu.tsx/filtering.tsx
new file mode 100644
index 0000000000..63a2f8b817
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/table/table-header-menu.tsx/filtering.tsx
@@ -0,0 +1,86 @@
+import Checkbox from '@mui/material/Checkbox';
+import Typography from '@mui/material/Typography';
+import List from '@mui/material/List';
+import Divider from '@mui/material/Divider';
+import ListItem from '@mui/material/ListItem';
+import { t } from 'i18next';
+import { colorPalette } from '@/styles/color-palette';
+
+interface FilteringOption {
+ name: string;
+ option: T;
+}
+
+interface FilteringProps {
+ filteringOptions: FilteringOption[];
+ isChecked: (option: T) => boolean;
+ setFiltering: (option: T) => void;
+ clear: () => void;
+ isMobile?: boolean;
+}
+
+export function Filtering({
+ filteringOptions,
+ isChecked,
+ setFiltering,
+ clear,
+ isMobile = true,
+}: FilteringProps) {
+ return (
+
+ {isMobile ? (
+
+ {t('components.table.filter')}
+
+ ) : null}
+ {filteringOptions.map(({ option, name }) => {
+ return (
+
+ {
+ if (isChecked(option)) {
+ clear();
+ return;
+ }
+ setFiltering(option);
+ }}
+ sx={{ paddingLeft: 0, ':hover': { background: 'none' } }}
+ />
+
+
+ {name}
+
+
+
+ );
+ })}
+ {isMobile ? (
+ <>
+
+
+ {
+ clear();
+ }}
+ variant="buttonMedium"
+ >
+ {t('components.table.clearBtn')}
+
+
+ >
+ ) : null}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/table/table-header-menu.tsx/sorting.tsx b/packages/apps/human-app/frontend/src/components/ui/table/table-header-menu.tsx/sorting.tsx
new file mode 100644
index 0000000000..b3156d9fee
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/table/table-header-menu.tsx/sorting.tsx
@@ -0,0 +1,49 @@
+import { Divider, Typography } from '@mui/material';
+import List from '@mui/material/List';
+import ListItemText from '@mui/material/ListItemText';
+import { t } from 'i18next';
+import { colorPalette } from '@/styles/color-palette';
+
+interface SortingMenuProps {
+ sortingOptions: { label: string; sortCallback: () => void }[];
+ clear: () => void;
+}
+
+export function Sorting({ sortingOptions, clear }: SortingMenuProps) {
+ return (
+
+
+ {t('components.table.sort')}
+
+ {sortingOptions.map(({ label, sortCallback }) => {
+ return (
+ {
+ sortCallback();
+ }}
+ sx={{ padding: '0.2rem 0.5rem', cursor: 'pointer' }}
+ >
+
+ {label}
+
+
+ );
+ })}
+
+
+
+ {t('components.table.clearBtn')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/table/table-query-context.tsx b/packages/apps/human-app/frontend/src/components/ui/table/table-query-context.tsx
new file mode 100644
index 0000000000..50bc898ca6
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/table/table-query-context.tsx
@@ -0,0 +1,66 @@
+import React, { createContext, useState } from 'react';
+import type {
+ MRT_SortingState,
+ MRT_PaginationState,
+} from 'material-react-table';
+
+const DEFAULT_PAGINATION = {
+ pageIndex: 1,
+ pageSize: 5,
+};
+
+export interface TableQueryContext {
+ actions: {
+ setSorting: React.Dispatch>;
+ setPagination: React.Dispatch>;
+ setFiltering: React.Dispatch>;
+ };
+ fields: {
+ sorting: MRT_SortingState;
+ pagination: MRT_PaginationState;
+ filtering: string[];
+ };
+}
+
+export const TableQueryContext = createContext({
+ actions: {
+ setSorting: () => undefined,
+ setPagination: () => undefined,
+ setFiltering: () => undefined,
+ },
+ fields: {
+ sorting: [],
+ pagination: DEFAULT_PAGINATION,
+ filtering: [],
+ },
+});
+
+export function TableQueryContextProvider({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const [sorting, setSorting] = useState([]);
+ const [pagination, setPagination] =
+ useState(DEFAULT_PAGINATION);
+ const [filtering, setFiltering] = useState([]);
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/table/table-query-hook.ts b/packages/apps/human-app/frontend/src/components/ui/table/table-query-hook.ts
new file mode 100644
index 0000000000..36352ded4c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/table/table-query-hook.ts
@@ -0,0 +1,4 @@
+import { useContext } from 'react';
+import { TableQueryContext } from '@/components/ui/table/table-query-context';
+
+export const useTableQuery = () => useContext(TableQueryContext);
diff --git a/packages/apps/human-app/frontend/src/components/ui/top-notification.tsx b/packages/apps/human-app/frontend/src/components/ui/top-notification.tsx
new file mode 100644
index 0000000000..a23525bc45
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/top-notification.tsx
@@ -0,0 +1,55 @@
+import CheckCircleIcon from '@mui/icons-material/CheckCircle';
+import MuiAlert from '@mui/material/Alert';
+import type { AlertProps as MuiAlertProps } from '@mui/material/Alert';
+import { Typography } from '@mui/material';
+import ErrorIcon from '@mui/icons-material/Error';
+import { colorPalette } from '@/styles/color-palette';
+import { breakpoints } from '@/styles/theme';
+
+export type TopNotificationType = 'success' | 'warning';
+
+const getIcon = (type: TopNotificationType) => {
+ switch (type) {
+ case 'success':
+ return ;
+
+ case 'warning':
+ return ;
+ }
+};
+
+type TopNotificationProps = MuiAlertProps & {
+ type: TopNotificationType;
+};
+
+export function TopNotification({
+ children,
+ type,
+ ...rest
+}: TopNotificationProps) {
+ const icon = getIcon(type);
+ const color =
+ type === 'success' ? colorPalette.success.main : colorPalette.primary.light;
+ return (
+
+
+ {children}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/components/ui/ui-example.tsx b/packages/apps/human-app/frontend/src/components/ui/ui-example.tsx
new file mode 100644
index 0000000000..7f678f31fd
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/components/ui/ui-example.tsx
@@ -0,0 +1,291 @@
+import Grid from '@mui/material/Grid';
+import Stack from '@mui/material/Stack';
+import Typography from '@mui/material/Typography';
+import { Button } from '@/components/ui/button';
+import { Loader } from '@/components/ui/loader';
+import { colorPalette } from '@/styles/color-palette';
+import { MODAL_STATE, useModalStore } from '@/components/ui/modal/modal.store';
+import {
+ HomepageLogoIcon,
+ HomepageUserIcon,
+ HomepageWorkIcon,
+ HumanLogoIcon,
+ HumanLogoCircleIcon,
+ BackArrowIcon,
+ ChatIcon,
+ HandIcon,
+ InfoIcon,
+ RefreshIcon,
+ UserFilledIcon,
+ UserOutlinedIcon,
+ UserSecondaryIcon,
+ WorkIcon,
+ WorkSecondaryIcon,
+ HumanLogoNavbarIcon,
+ DiscordIcon,
+ HelpIcon,
+ MobileHeaderIcon,
+ ProfileIcon,
+ CheckmarkIcon,
+ LockerIcon,
+ FiltersButtonIcon,
+ SortArrow,
+} from '@/components/ui/icons';
+import { TableExample } from '@/pages/playground/table-example/table-example';
+import { Alert } from '@/components/ui/alert';
+import { ConnectWalletBtn } from '@/components/ui/connect-wallet-btn';
+
+export function UiExample() {
+ const { openModal } = useModalStore();
+ return (
+
+
+ Fonts
+
+
+
+ IMPORTANT - To use Header 1 - 5 you have to add into Typography a prop
+ component
+
+
+
+
+ H1 / Inter Extrabold 80
+
+
+
+ H2 / Inter Semibold 60
+
+
+
+ H3 / Inter Regular 48
+
+
+
+ H4 / Inter Semibold 34
+
+
+
+ H5 / Inter Regular 24
+
+
+
+ H6 / Inter Medium 20
+
+
+
+ Subtitle 1 / Inter Regular 16
+
+
+
+ Subtitle 2 / Inter Semibold 14
+
+
+ Body 1 / Inter Regular 16
+
+ Body 1 / Inter Regular 14
+
+ Body 3 / Inter Medium 16
+
+
+ Button large / Inter Semibold 15
+
+
+
+ Button medium / Inter Semibold 14
+
+
+
+ Button small / Inter Semibold 13
+
+
+ Caption / Inter Regular 12
+ Overline / Inter Regular 12
+
+ Avatar Letter / Inter Regular 20
+
+
+ Input Label / Inter Regular 12
+
+
+ Helper Text / Inter Regular 12
+
+
+ Input Text / Inter Regular 16
+
+ Tooltip / Inter Medium 12
+
+ Input Under line / Inter Semibold 12
+
+
+
+
Buttons
+
+ Text
+ Contained
+ Outlined
+
+ Disabled
+
+
+ Loading
+
+
+
+
Button sizes
+
+
+
+ small
+
+
+
+
+ medium
+
+
+
+
+ large
+
+
+
+
+
+
+ Full width
+
+
+
+
Connect wallet button
+
+
+
Loader
+
+
+
+
+
+
+
Icons
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Modal
+
+
{
+ openModal(MODAL_STATE.MODAL_EXAMPLE);
+ }}
+ >
+ Open modal
+
+
+
Table
+
+
+
Alert
+
+
+ An error has occurred, please try again.
+
+
+ Your password has been successfully updated!
+
+
+ We have switched to the Polygon network. You’ll need to replace your
+ Ethereum wallet address with one connected to Polygon.
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/contexts/jwt-expiration-check.tsx b/packages/apps/human-app/frontend/src/contexts/jwt-expiration-check.tsx
new file mode 100644
index 0000000000..c86809e59b
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/contexts/jwt-expiration-check.tsx
@@ -0,0 +1,40 @@
+import type React from 'react';
+import { useEffect } from 'react';
+import { useLocation } from 'react-router-dom';
+import { useGetAccessTokenMutation } from '@/api/servieces/common/get-access-token';
+import { useWeb3Auth } from '@/auth-web3/use-web3-auth';
+import { useAuth } from '@/auth/use-auth';
+
+export function JWTExpirationCheck({
+ children,
+}: {
+ children: React.ReactElement;
+}) {
+ const web3Auth = useWeb3Auth();
+ const web2Auth = useAuth();
+ const location = useLocation();
+ const { mutate: getAccessTokenMutation } = useGetAccessTokenMutation();
+
+ useEffect(() => {
+ const web3TokenExpired = Boolean(
+ web3Auth.user?.exp && web3Auth.user.exp < Date.now() / 1000
+ );
+ if (web3TokenExpired) {
+ getAccessTokenMutation('web3');
+ }
+
+ const web2TokenExpired = Boolean(
+ web2Auth.user?.exp && web2Auth.user.exp < Date.now() / 1000
+ );
+ if (web2TokenExpired) {
+ getAccessTokenMutation('web2');
+ }
+ }, [
+ location,
+ web3Auth.user?.exp,
+ web2Auth.user?.exp,
+ getAccessTokenMutation,
+ ]);
+
+ return children;
+}
diff --git a/packages/apps/human-app/frontend/src/contexts/wallet-connect.tsx b/packages/apps/human-app/frontend/src/contexts/wallet-connect.tsx
new file mode 100644
index 0000000000..89febe5407
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/contexts/wallet-connect.tsx
@@ -0,0 +1,142 @@
+import {
+ createWeb3Modal,
+ defaultConfig,
+ useWeb3Modal,
+ useWeb3ModalAccount,
+} from '@web3modal/ethers/react';
+import type { JsonRpcSigner, BrowserProvider, Eip1193Provider } from 'ethers';
+import React, { createContext, useEffect, useState } from 'react';
+import type { UseMutationResult } from '@tanstack/react-query';
+import { useWeb3Provider } from '@/hooks/use-web3-provider';
+import { env } from '@/shared/env';
+import type { ResponseError } from '@/shared/types/global.type';
+import { chains } from '@/smart-contracts/chains';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+const projectId = env.VITE_WALLET_CONNECT_PROJECT_ID;
+
+const metadata = {
+ name: env.VITE_DAPP_META_NAME,
+ description: env.VITE_DAPP_META_DESCRIPTION,
+ url: env.VITE_DAPP_META_URL,
+ icons: env.VITE_DAPP_ICONS,
+};
+
+const ethersConfig = defaultConfig({
+ metadata,
+});
+createWeb3Modal({
+ ethersConfig,
+ chains,
+ projectId,
+ enableAnalytics: true,
+});
+export interface CommonWalletConnectContext {
+ openModal: () => Promise;
+ web3ProviderMutation: UseMutationResult<
+ {
+ provider: BrowserProvider;
+ signer: JsonRpcSigner;
+ },
+ ResponseError,
+ Eip1193Provider
+ >;
+ initializing: boolean;
+}
+
+interface ConnectedAccount {
+ isConnected: true;
+ chainId: number;
+ address: `0x${string}`;
+ signMessage: (message: string) => Promise;
+}
+
+interface DisconnectedAccount {
+ isConnected: false;
+ chainId?: never;
+ address?: never;
+ signMessage?: (message: string) => Promise;
+}
+
+export type WalletConnectContextConnectedAccount = CommonWalletConnectContext &
+ ConnectedAccount;
+
+type WalletConnectContextDisconnectedAccount = CommonWalletConnectContext &
+ DisconnectedAccount;
+
+export const WalletConnectContext = createContext<
+ | WalletConnectContextConnectedAccount
+ | WalletConnectContextDisconnectedAccount
+ | null
+>(null);
+
+export function WalletConnectProvider({
+ children,
+}: {
+ children: React.ReactNode;
+}) {
+ const [initializing, setInitializing] = useState(true);
+ const web3ProviderMutation = useWeb3Provider();
+ const { open } = useWeb3Modal();
+ const { address, chainId, isConnected } = useWeb3ModalAccount();
+
+ const openModal = async () => {
+ await open();
+ };
+
+ useEffect(() => {
+ if (
+ web3ProviderMutation.status === 'error' ||
+ web3ProviderMutation.status === 'success'
+ ) {
+ setInitializing(false);
+ }
+ }, [web3ProviderMutation]);
+
+ return (
+ {
+ try {
+ const signature =
+ await web3ProviderMutation.data.signer.signMessage(message);
+ return signature;
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+ },
+ initializing,
+ }
+ : {
+ isConnected: false,
+ web3ProviderMutation,
+ openModal,
+ signMessage: async (message: string) => {
+ if (web3ProviderMutation.data) {
+ try {
+ const signature =
+ await web3ProviderMutation.data.signer.signMessage(
+ message
+ );
+ return signature;
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+ }
+ return Promise.resolve(undefined);
+ },
+ initializing,
+ }
+ }
+ >
+ {children}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-background-store.tsx b/packages/apps/human-app/frontend/src/hooks/use-background-store.tsx
new file mode 100644
index 0000000000..8e265f7636
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-background-store.tsx
@@ -0,0 +1,18 @@
+import { create } from 'zustand';
+import { colorPalette } from '@/styles/color-palette';
+
+interface BackgroundStore {
+ backgroundColor: string;
+ setWhiteBackground: () => void;
+ setGrayBackground: () => void;
+}
+
+export const useBackgroundColorStore = create((set) => ({
+ backgroundColor: colorPalette.white,
+ setWhiteBackground: () => {
+ set((state) => ({ ...state, backgroundColor: colorPalette.white }));
+ },
+ setGrayBackground: () => {
+ set((state) => ({ ...state, backgroundColor: colorPalette.paper.main }));
+ },
+}));
diff --git a/packages/apps/human-app/frontend/src/hooks/use-count-down.tsx b/packages/apps/human-app/frontend/src/hooks/use-count-down.tsx
new file mode 100644
index 0000000000..ec78b185f2
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-count-down.tsx
@@ -0,0 +1,35 @@
+import { useEffect, useState } from 'react';
+import type { ParsedDate } from '@/shared/helpers/counter-helpers';
+import { parseDate } from '@/shared/helpers/counter-helpers';
+
+export function useCountDown(
+ timeBetweenNowAndEndDateProp: number,
+ onFinish?: () => void
+): ParsedDate | null {
+ const [timeDifference, setTimeDifference] = useState(
+ timeBetweenNowAndEndDateProp
+ );
+ const [isDone, setIsDone] = useState(false);
+
+ useEffect(() => {
+ const intervalId = setInterval(() => {
+ if (timeDifference < 0) {
+ setIsDone(true);
+ if (onFinish) {
+ onFinish();
+ }
+ return;
+ }
+ setTimeDifference((timestamp) => timestamp - 1000);
+ }, 1000);
+
+ return () => {
+ clearInterval(intervalId);
+ };
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- ...
+ }, []);
+
+ return isDone
+ ? { days: 0, minutes: 0, hours: 0, seconds: 0 }
+ : parseDate(timeDifference);
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-hcaptcha-labeling-notifications.tsx b/packages/apps/human-app/frontend/src/hooks/use-hcaptcha-labeling-notifications.tsx
new file mode 100644
index 0000000000..547ecf5d4e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-hcaptcha-labeling-notifications.tsx
@@ -0,0 +1,31 @@
+import { t } from 'i18next';
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { wait } from '@/shared/helpers/wait';
+import type { ResponseError } from '@/shared/types/global.type';
+
+export function useHCaptchaLabelingNotifications() {
+ const { setTopNotification, closeNotification } =
+ useProtectedLayoutNotification();
+
+ const onSuccess = async () => {
+ setTopNotification({
+ type: 'success',
+ content: t('worker.hcaptchaLabelingStats.solvedSuccess'),
+ });
+
+ await wait(2000);
+ closeNotification();
+ };
+ const onError = async (error: ResponseError) => {
+ setTopNotification({
+ type: 'warning',
+ content: defaultErrorMessage(error),
+ });
+
+ await wait(2000);
+ closeNotification();
+ };
+
+ return { onSuccess, onError };
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-is-hcaptcha-labeling-page.ts b/packages/apps/human-app/frontend/src/hooks/use-is-hcaptcha-labeling-page.ts
new file mode 100644
index 0000000000..a5b0f95f61
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-is-hcaptcha-labeling-page.ts
@@ -0,0 +1,7 @@
+import { useLocation } from 'react-router-dom';
+import { routerPaths } from '@/router/router-paths';
+
+export function useIsHCaptchaLabelingPage() {
+ const location = useLocation();
+ return location.pathname === routerPaths.worker.HcaptchaLabeling;
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-is-mobile.tsx b/packages/apps/human-app/frontend/src/hooks/use-is-mobile.tsx
new file mode 100644
index 0000000000..4bd11f49fc
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-is-mobile.tsx
@@ -0,0 +1,10 @@
+import type { Breakpoint } from '@mui/material';
+import { useTheme, useMediaQuery } from '@mui/material';
+
+export const useIsMobile = (breakpoint?: Breakpoint) => {
+ const theme = useTheme();
+ const isMobile = !useMediaQuery(
+ theme.breakpoints.up(breakpoint ? breakpoint : 'md')
+ );
+ return isMobile;
+};
diff --git a/packages/apps/human-app/frontend/src/hooks/use-job-types-oracles-table.tsx b/packages/apps/human-app/frontend/src/hooks/use-job-types-oracles-table.tsx
new file mode 100644
index 0000000000..f2b98113fa
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-job-types-oracles-table.tsx
@@ -0,0 +1,19 @@
+/* eslint-disable camelcase -- ... */
+import { create } from 'zustand';
+
+export interface JobsTypesOraclesFilterStore {
+ selected_job_types: string[];
+ selectJobType: (jobType: string[]) => void;
+}
+
+export const useJobsTypesOraclesFilter = create(
+ (set) => ({
+ selected_job_types: [],
+ selectJobType: (jobTypes: string[]) => {
+ set((state) => ({
+ ...state,
+ selected_job_types: jobTypes.map((jobType) => jobType.toLowerCase()),
+ }));
+ },
+ })
+);
diff --git a/packages/apps/human-app/frontend/src/hooks/use-jobs-filter-store.tsx b/packages/apps/human-app/frontend/src/hooks/use-jobs-filter-store.tsx
new file mode 100644
index 0000000000..49217b5662
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-jobs-filter-store.tsx
@@ -0,0 +1,94 @@
+/* eslint-disable camelcase -- api params*/
+import { create } from 'zustand';
+import type { PageSize } from '@/shared/types/entity.type';
+
+export interface JobsFilterStoreProps {
+ filterParams: {
+ sort?: 'ASC' | 'DESC';
+ sort_field?:
+ | 'chain_id'
+ | 'job_type'
+ | 'reward_amount'
+ | 'created_at'
+ | 'escrow_address';
+ network?: 'MATIC' | 'POLYGON';
+ // TODO add allowed job types
+ job_type?: string;
+ status?:
+ | 'ACTIVE'
+ | 'COMPLETED'
+ | 'CANCELED'
+ | 'VALIDATION'
+ | 'EXPIRED'
+ | 'REJECTED';
+ escrow_address?: string;
+ page: number;
+ page_size: PageSize;
+ fields: string[];
+ chain_id?: number;
+ };
+ setFilterParams: (
+ partialParams: Partial
+ ) => void;
+ resetFilterParams: () => void;
+ setSearchEscrowAddress: (escrow_address: string) => void;
+ setOracleAddress: (oracleAddress: string) => void;
+ setPageParams: (pageIndex: number, pageSize: PageSize) => void;
+}
+
+const initialFiltersState = {
+ page: 0,
+ page_size: 5,
+ fields: ['reward_amount', 'job_description', 'reward_token'],
+ status: 'ACTIVE',
+} satisfies Pick<
+ JobsFilterStoreProps['filterParams'],
+ 'page_size' | 'page' | 'fields' | 'status'
+>;
+
+export const useJobsFilterStore = create((set) => ({
+ filterParams: initialFiltersState,
+ setFilterParams: (
+ partialParams: Partial
+ ) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ ...partialParams,
+ page: 0,
+ },
+ }));
+ },
+ setPageParams: (pageIndex: number, pageSize: PageSize) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ page: pageIndex,
+ page_size: pageSize,
+ },
+ }));
+ },
+ resetFilterParams: () => {
+ set({ filterParams: initialFiltersState });
+ },
+ setSearchEscrowAddress: (escrow_address: string) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ escrow_address,
+ },
+ }));
+ },
+ setOracleAddress: (oracleAddress: string) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ oracle_address: oracleAddress,
+ },
+ }));
+ },
+}));
diff --git a/packages/apps/human-app/frontend/src/hooks/use-jobs-notifications.tsx b/packages/apps/human-app/frontend/src/hooks/use-jobs-notifications.tsx
new file mode 100644
index 0000000000..a1e5be884d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-jobs-notifications.tsx
@@ -0,0 +1,29 @@
+import { t } from 'i18next';
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { wait } from '@/shared/helpers/wait';
+
+export const useJobsNotifications = () => {
+ const { setTopNotification, closeNotification } =
+ useProtectedLayoutNotification();
+
+ const onJobAssignmentSuccess = async () => {
+ setTopNotification({
+ content: t('worker.jobs.successFullyAssignedJob'),
+ type: 'success',
+ });
+ await wait(5000);
+ closeNotification();
+ };
+
+ const onJobAssignmentError = async (error: unknown) => {
+ setTopNotification({
+ content: defaultErrorMessage(error),
+ type: 'warning',
+ });
+ await wait(5000);
+ closeNotification();
+ };
+
+ return { onJobAssignmentSuccess, onJobAssignmentError };
+};
diff --git a/packages/apps/human-app/frontend/src/hooks/use-kyc-notification.tsx b/packages/apps/human-app/frontend/src/hooks/use-kyc-notification.tsx
new file mode 100644
index 0000000000..817e139493
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-kyc-notification.tsx
@@ -0,0 +1,14 @@
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import type { ResponseError } from '@/shared/types/global.type';
+
+export function useKycErrorNotifications() {
+ const { setTopNotification } = useProtectedLayoutNotification();
+
+ return (error: ResponseError) => {
+ setTopNotification({
+ type: 'warning',
+ content: defaultErrorMessage(error),
+ });
+ };
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-location-state.tsx b/packages/apps/human-app/frontend/src/hooks/use-location-state.tsx
new file mode 100644
index 0000000000..e480cf8254
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-location-state.tsx
@@ -0,0 +1,44 @@
+/* eslint-disable @typescript-eslint/no-unsafe-member-access -- that's ok because we validate this members with zod */
+import { useEffect, useState } from 'react';
+import type { Location } from 'react-router-dom';
+import { useLocation, useNavigate } from 'react-router-dom';
+import type { z } from 'zod';
+import { routerPaths } from '@/router/router-paths';
+
+interface UseLocationStateProps {
+ schema: z.ZodSchema;
+ locationStorage?: keyof Location;
+ keyInStorage?: string;
+ onErrorRedirectPath?: string;
+}
+
+export function useLocationState({
+ keyInStorage,
+ onErrorRedirectPath = routerPaths.homePage,
+ locationStorage = 'state',
+ schema,
+}: UseLocationStateProps) {
+ const location = useLocation();
+ const navigate = useNavigate();
+ const [fieldFromState, setFieldFromState] = useState();
+
+ useEffect(() => {
+ try {
+ const storage = (
+ keyInStorage
+ ? location[locationStorage]?.[keyInStorage]
+ : location[locationStorage]
+ ) as unknown;
+
+ const validFiled = schema.parse(storage);
+ setFieldFromState(validFiled);
+ } catch {
+ navigate(onErrorRedirectPath, { replace: true });
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- call this effect once
+ }, []);
+
+ return {
+ field: fieldFromState,
+ };
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-my-jobs-filter-store.tsx b/packages/apps/human-app/frontend/src/hooks/use-my-jobs-filter-store.tsx
new file mode 100644
index 0000000000..fcbb1d9eeb
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-my-jobs-filter-store.tsx
@@ -0,0 +1,95 @@
+/* eslint-disable camelcase -- api params*/
+import { create } from 'zustand';
+import type { PageSize } from '@/shared/types/entity.type';
+
+export const jobStatuses = [
+ 'ACTIVE',
+ 'COMPLETED',
+ 'CANCELED',
+ 'VALIDATION',
+ 'EXPIRED',
+ 'REJECTED',
+] as const;
+
+type JobStatus = (typeof jobStatuses)[number];
+
+export interface MyJobsFilterStoreProps {
+ filterParams: {
+ sort?: 'ASC' | 'DESC';
+ sort_field?: 'chain_id' | 'job_type' | 'reward_amount' | 'expires_at';
+ job_type?: string;
+ status?: JobStatus;
+ escrow_address?: string;
+ page: number;
+ page_size: PageSize;
+ chain_id?: number;
+ };
+ availableJobTypes: string[];
+ setFilterParams: (
+ partialParams: Partial
+ ) => void;
+ resetFilterParams: () => void;
+ setSearchEscrowAddress: (escrow_address: string) => void;
+ setOracleAddress: (oracleAddress: string) => void;
+ setAvailableJobTypes: (jobTypes: string[]) => void;
+ setPageParams: (pageIndex: number, pageSize: PageSize) => void;
+}
+
+const initialFiltersState = {
+ page: 0,
+ page_size: 5,
+} as const;
+
+export const useMyJobsFilterStore = create((set) => ({
+ filterParams: initialFiltersState,
+ availableJobTypes: [],
+ setFilterParams: (
+ partialParams: Partial
+ ) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ ...partialParams,
+ page: 0,
+ },
+ }));
+ },
+ setPageParams: (pageIndex: number, pageSize: PageSize) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ page: pageIndex,
+ page_size: pageSize,
+ },
+ }));
+ },
+ resetFilterParams: () => {
+ set({ filterParams: initialFiltersState });
+ },
+ setSearchEscrowAddress: (escrow_address: string) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ escrow_address,
+ },
+ }));
+ },
+ setOracleAddress: (oracleAddress: string) => {
+ set((state) => ({
+ ...state,
+ filterParams: {
+ ...state.filterParams,
+ address: oracleAddress,
+ },
+ }));
+ },
+ setAvailableJobTypes: (jobTypes: string[]) => {
+ set((state) => ({
+ ...state,
+ jobTypes,
+ }));
+ },
+}));
diff --git a/packages/apps/human-app/frontend/src/hooks/use-protected-layout-notifications.tsx b/packages/apps/human-app/frontend/src/hooks/use-protected-layout-notifications.tsx
new file mode 100644
index 0000000000..279b63688e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-protected-layout-notifications.tsx
@@ -0,0 +1,12 @@
+import { useContext } from 'react';
+import { ProtectedLayoutContext } from '@/components/layout/protected/layout-notification-context';
+
+export function useProtectedLayoutNotification() {
+ const context = useContext(ProtectedLayoutContext);
+
+ if (!context) {
+ throw new Error('No context for useProtectedLayoutNotification');
+ }
+
+ return context;
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-register-address-notifications.tsx b/packages/apps/human-app/frontend/src/hooks/use-register-address-notifications.tsx
new file mode 100644
index 0000000000..9e6b6a43cc
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-register-address-notifications.tsx
@@ -0,0 +1,20 @@
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import type { ResponseError } from '@/shared/types/global.type';
+
+export function useRegisterAddressNotifications() {
+ const { setTopNotification, closeNotification } =
+ useProtectedLayoutNotification();
+
+ const onSuccess = () => {
+ closeNotification();
+ };
+ const onError = (error: ResponseError) => {
+ setTopNotification({
+ type: 'warning',
+ content: defaultErrorMessage(error),
+ });
+ };
+
+ return { onSuccess, onError };
+}
diff --git a/packages/apps/human-app/frontend/src/hooks/use-wallet-connect.tsx b/packages/apps/human-app/frontend/src/hooks/use-wallet-connect.tsx
new file mode 100644
index 0000000000..0c855b5849
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-wallet-connect.tsx
@@ -0,0 +1,12 @@
+import { useContext } from 'react';
+import { WalletConnectContext } from '@/contexts/wallet-connect';
+
+export const useWalletConnect = () => {
+ const context = useContext(WalletConnectContext);
+
+ if (!context) {
+ throw new Error('Cannot use context of useWalletConnect');
+ }
+
+ return context;
+};
diff --git a/packages/apps/human-app/frontend/src/hooks/use-web3-provider.tsx b/packages/apps/human-app/frontend/src/hooks/use-web3-provider.tsx
new file mode 100644
index 0000000000..16017c827c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/hooks/use-web3-provider.tsx
@@ -0,0 +1,38 @@
+import { useMutation } from '@tanstack/react-query';
+import {
+ useWeb3ModalAccount,
+ useWeb3ModalProvider,
+} from '@web3modal/ethers/react';
+import type { Eip1193Provider } from 'ethers';
+import { BrowserProvider } from 'ethers';
+import { useEffect } from 'react';
+import { checkNetwork } from '@/smart-contracts/check-network';
+
+const getSignerAndProvider = async (walletProvider: Eip1193Provider) => {
+ const provider = new BrowserProvider(walletProvider);
+ const signer = await provider.getSigner();
+ const network = await provider.getNetwork();
+ checkNetwork(network);
+
+ return {
+ provider,
+ signer,
+ };
+};
+
+export function useWeb3Provider() {
+ const { chainId } = useWeb3ModalAccount();
+ const { walletProvider } = useWeb3ModalProvider();
+ const useSignerAndProviderMutation = useMutation({
+ mutationFn: getSignerAndProvider,
+ });
+
+ useEffect(() => {
+ if (walletProvider) {
+ useSignerAndProviderMutation.mutate(walletProvider);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- not nesseccary
+ }, [walletProvider, chainId]);
+
+ return useSignerAndProviderMutation;
+}
diff --git a/packages/apps/human-app/frontend/src/i18n/en.json b/packages/apps/human-app/frontend/src/i18n/en.json
new file mode 100644
index 0000000000..c2416f5778
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/i18n/en.json
@@ -0,0 +1,395 @@
+{
+ "humanCurrencySymbol": "HMT",
+ "inputMasks": {
+ "humanCurrencySuffix": " HMT",
+ "percentSuffix": "%",
+ "plusPrefix": "+"
+ },
+ "dashboard": {},
+ "protectedPagesHeaders": {
+ "profile": "Profile",
+ "jobsDiscovery": "Jobs Discovery",
+ "hcaptchaLabeling": "hCaptcha Labeling",
+ "jobs": "Jobs"
+ },
+ "web3ProtectedPagesHeaders": {
+ "profile": "Profile"
+ },
+ "validation": {
+ "required": "Required",
+ "min": "Min {{count}} characters",
+ "max": "Max {{count}} characters",
+ "passwordWeak": "Password should be at least 8 characters long and contain at least one uppercase and one lowercase letter, one number and one special character",
+ "passwordMismatch": "Passwords are not the same",
+ "password8Chars": "8 characters",
+ "passwordUppercase": "1 uppercase (A-Z)",
+ "passwordLowercase": "1 lowercase (a-z)",
+ "passwordNumeric": "1 numeric (0-9)",
+ "passwordSpecialCharacter": "1 special character (@#$%^&+=!*])",
+ "captcha": "Please complete the captcha",
+ "passwordMissing": "Please enter your password.",
+ "invalidEmail": "Please enter a valid email address."
+ },
+ "errors": {
+ "errorWithMessage": "Error with message: {{message}}",
+ "errorWithStatusCode": "Error with status code: {{code}}",
+ "unknown": "An error occurred, please try again.",
+ "unknownNetwork": "Unknown network",
+ "jsonRpcError": "JSON-RPC error",
+ "unsupportedNetwork": "Network selected in wallet is unsupported.",
+ "unsupportedNetworkWithName": "Network '{{networkName}}' is unsupported."
+ },
+ "components": {
+ "multiSelect": {
+ "allFields": "All fields",
+ "andMore": "(and {{number}} more)",
+ "clearAll": "Clear all"
+ },
+ "breadcrumb": {
+ "back": "Back"
+ },
+ "navbar": {
+ "humanProtocol": "HUMAN Protocol",
+ "howItWorks": "How It Works"
+ },
+ "DrawerNavigation": {
+ "jobs": "Jobs",
+ "captchaLabelling": "hCaptcha labelling",
+ "jobsDiscovery": "Jobs discovery",
+ "profile": "Profile",
+ "help": "Help",
+ "logout": "Log Out"
+ },
+ "footer": {
+ "privacyPolicy": "Privacy Policy",
+ "termsOfService": "Terms of Service",
+ "humanProtocol": "HUMAN Protocol",
+ "copyrightNote": "© 2021 HPF. HUMAN Protocol® is a registered trademark"
+ },
+ "table": {
+ "clearBtn": "Clear",
+ "sort": "Sort",
+ "filter": "Filter"
+ },
+ "modal": {
+ "header": {
+ "closeBtn": "Cancel"
+ }
+ },
+ "wallet": {
+ "connectBtn": {
+ "disconnect": "Disconnect Wallet",
+ "connect": "Connect Wallet"
+ }
+ },
+ "pageCardError": {
+ "reload": "Reload",
+ "goHome": "Back to home page"
+ }
+ },
+ "homepage": {
+ "humanApp": "HUMAN App",
+ "completeJobs": "Complete jobs, earn HMT.",
+ "logIn": "Log In",
+ "signUp": "Sign Up",
+ "signIn": "Sign In",
+ "workerSignIn": "Worker Sign In",
+ "operatorSignIn": "Operator Sign In",
+ "welcome": "Welcome",
+ "howWillUse": "How will you use HUMAN App?",
+ "selectOption": "Please select an option below.",
+ "iWantToEarn": "I want to earn HMT",
+ "completeTask": "Complete simple tasks and get paid.",
+ "workAnywhere": "Work anywhere, any time.",
+ "signUpToComplete": "Sign Up to Complete Tasks",
+ "joinAsOperator": "I want to join as an operator",
+ "runAsOracle": "Run an Oracle, or other essential service, and earn fees.",
+ "becomePartner": "Become a HUMAN App partner.",
+ "signAsOperator": "Sign Up as an Operator",
+ "termsAndConditions": "Terms & conditions",
+ "cancel": "Cancel"
+ },
+ "worker": {
+ "signUpForm": {
+ "fields": {
+ "createPassword": "Create Password",
+ "password": "Create Password",
+ "confirmPassword": "Confirm Password",
+ "email": "your@email.com"
+ },
+ "errors": {
+ "emailTaken": "Email is already taken. Please sign in."
+ },
+ "title": "Sign Up",
+ "submitBtn": "Sign Up",
+ "passwordDetailedValidation": "Password must contain at least:",
+ "termsOfServiceAndPrivacyPolicy": "By clicking Sign Up, you agree to our <1>Terms of Service1> and that you have read our <2>Privacy Policy2>"
+ },
+ "signInForm": {
+ "fields": {
+ "password": "Password",
+ "email": "your@email.com"
+ },
+ "errors": {
+ "invalidCredentials": "Incorrect email or password!"
+ },
+ "title": "Sign In",
+ "submitBtn": "Sign In",
+ "forgotPassword": "Forgot Password?"
+ },
+ "sendEmailVerification": {
+ "title": "Verify Email",
+ "btn": "Resend Verification Email",
+ "paragraph1": "Your email address <1>{{email}}1> is not verified.",
+ "paragraph2": "<1>Having trouble?1> Please <2>Contact Support2>",
+ "successResent": "Verification email has been successfully resent."
+ },
+ "verifyEmail": {
+ "title": "Verify Email",
+ "btn": "Resend Verification Email",
+ "paragraph1": "We've sent an email to <1>{{email}}1>, please check your inbox and verify your email.",
+ "paragraph2": "The verification link is valid for 24 hours.",
+ "paragraph3": "<1>Can't find our email?1> If you can't find the email in your inbox please check the spam folder.",
+ "paragraph4": "<1>Having trouble?1> Please <2>Contact Support2>",
+ "successResent": "Verification email has been successfully resent.",
+ "authError": "Log in before you resend email verification"
+ },
+ "emailVerification": {
+ "title": "Email Verified",
+ "description": "You are ready to go. Your email has been successfully verified!",
+ "btn": "Sign In"
+ },
+ "sendResetLinkForm": {
+ "fields": {
+ "email": "your@email.com"
+ },
+ "title": "Reset Password",
+ "description": "Please enter your email address. We will send you an email to reset your password.",
+ "submitBtn": "Send Email",
+ "invalidEmailError": "Please enter a valid email address.",
+ "noEmailError": "Please enter your email address."
+ },
+ "sendResetLinkSuccess": {
+ "title": "Reset password",
+ "paragraph1": "We've sent an email to <1>{{email}}1> Please check your inbox and verify your email.",
+ "paragraph2": "The verification link is valid for 24 hours.",
+ "paragraph3": "<1>Can't find our email?1> Please check your spam folder, or click below and we will send you a new one.",
+ "btn": "Resend Reset Password Email",
+ "paragraph4": "<1>Having trouble?1> Please <2>Contact Support2>"
+ },
+ "resetPassword": {
+ "fields": {
+ "createNewPassword": "Create New Password",
+ "confirm": "Confirm New Password"
+ },
+ "title": "Reset password",
+ "description": "Please enter your new password below.",
+ "btn": "Reset password"
+ },
+ "resetPasswordSuccess": {
+ "title": "Password Changed",
+ "description": "Your password has been changed successfully.",
+ "btn": "Sign In"
+ },
+ "profile": {
+ "profileHeader": "Profile",
+ "email": "Email",
+ "password": "Password",
+ "resetPassword": "Reset Password",
+ "completeKYC": "Complete KYC",
+ "KYCInProgress": "KYC in progress",
+ "confirmEmail": "Confirm email",
+ "kycCompleted": "KYC Completed",
+ "connectWallet": "Connect Wallet",
+ "walletConnected": "Wallet Connected ",
+ "addKYCInfoOnChain": "Add KYC Info On-chain",
+ "wrongWalletAddress": "Selected wallet address doesn't match the address assigned to the account.",
+ "kycInfoOnChainAdded": "KYC Info On-Chain Added",
+ "registerAddress": "Register address",
+ "emailNotifications": "Email Notifications",
+ "notificationsConsent": "I would like to be notified about News and Offers",
+ "topNotifications": {
+ "noKYC": "Please complete your profile! You still need to complete KYC, connect your wallet and add KYC info on-chain.",
+ "noWalletConnected": "Please complete your profile! You still need to connect your wallet and add KYC info on-chain.",
+ "registerAddress": "Register address"
+ }
+ },
+ "oraclesTable": {
+ "annotationTool": "Annotation tool",
+ "oracleAddress": "Oracle address",
+ "jobTypes": "Job types",
+ "seeJobs": "See jobs",
+ "allJobs": "All jobs"
+ },
+ "jobs": {
+ "successFullyAssignedJob": "Successfully assigned a job!",
+ "errorFetchingData": "There was an error while fetching data, please try again",
+ "availableJobs": "Available Jobs",
+ "myJobs": "My Jobs",
+ "jobsDiscovery": "Jobs Discovery",
+ "jobDescription": "Job description",
+ "escrowAddress": "Escrow address",
+ "network": "Network",
+ "rewardAmount": "Reward amount",
+ "jobType": "Job type",
+ "expiresAt": "Expires at",
+ "status": "Status",
+ "selectJob": "Select job",
+ "searchEscrowAddress": "Search escrow address",
+ "resign": "Resign",
+ "solve": "Solve",
+ "filter": "Filter",
+ "escrowAddressColumnId": "escrowAddress",
+ "Ethereum": "Ethereum",
+ "Polygon": "Polygon",
+ "sortDirection": {
+ "fromHighest": "From highest",
+ "fromLowest": "From lowest",
+ "furthestToNow": "Furthest to now",
+ "closestToNow": "Closest to now"
+ },
+ "mobileFilterDrawer": {
+ "sortBy": "Sort by",
+ "filters": "Filters",
+ "jobsStatus": {
+ "active": "Active",
+ "validation": "Validation",
+ "completed": "Completed",
+ "expired": "Expired",
+ "canceled": "Canceled",
+ "rejected": "Rejected"
+ },
+ "network": {
+ "matic": "Matic",
+ "polygon": "Polygon"
+ },
+ "jobType": {
+ "fortune": "Fortune"
+ }
+ },
+ "next": "Next"
+ },
+ "hcaptchaLabeling": {
+ "description": "To earn HMT, you must complete data-labeling tasks. Rewards will be automatically sent to your wallet according to a predefined schedule.",
+ "noJobs": "No jobs available at the moment. Please come back in:"
+ },
+ "enableHCaptchaLabeling": {
+ "description": "To earn HMT, you must enable data-labeling. Rewards will be automatically sent to your wallet according to a predefined schedule.",
+ "enableButton": "Enable Labeling"
+ },
+ "hcaptchaLabelingStats": {
+ "hCapchaStatistics": "hCapcha Statistics",
+ "statistics": "Statistics",
+ "allTime": "All Time",
+ "jobsServed": "Jobs served",
+ "jobsComplete": "Jobs complete",
+ "hmtEarned": "HMT earned",
+ "lastHour": "Last hour",
+ "earnedLastHour": "HMT earned in last hour",
+ "statisticsNotLive": "Statistics are not live. Please refresh to view live statistics.",
+ "solvedSuccess": "HCaptcha solved!"
+ }
+ },
+ "operator": {
+ "profile": {
+ "profileHeader": "Profile",
+ "about": {
+ "header": "About",
+ "role": "Role",
+ "status": {
+ "statusHeader": "Status",
+ "statusActivated": "Active",
+ "statusDeactivated": "Deactivated",
+ "statusActivateButton": "Activate",
+ "statusDeactivateButton": "Deactivate"
+ },
+ "fee": "Fee",
+ "url": "URL",
+ "webhookUrl": "Webhook URL",
+ "jobTypes": "Job Types",
+ "publicKey": "Public Key"
+ },
+ "activateBtn" : "Activate",
+ "disable": {
+ "disableBtn": "Deactivate",
+ "cannotDisable": "Cannot deactivate operator"
+ },
+ "statistics": {
+ "header": "Statistics",
+ "escrowsProcessed": "Escrows processed",
+ "escrowsActive": "Escrows active",
+ "escrowsCancelled": "Escrows cancelled",
+ "workersAmount": "Workers amount",
+ "assignmentsCompleted": "Assignments completed",
+ "assignmentsRejected": "Assignments rejected",
+ "assignmentsExpired": "Assignments expired"
+ }
+ },
+ "connectWallet": {
+ "title": "Setup Operator",
+ "description": "Please use the button bellow to connect your wallet and sign up as an operator.",
+ "connect": "Connect Wallet",
+ "disconnect": "Disconnect",
+ "successAlert": "Wallet successfully connected",
+ "setupOperator": "Setup Operator"
+ },
+ "addStake": {
+ "title": "Setup Operator",
+ "formHeader": "Stake",
+ "label": "Staked amount",
+ "description": "Please add bellow the amount to stake",
+ "actionBtn": "Add Stake",
+ "nextBtn": "Next",
+ "skipBtn": "Skip"
+ },
+ "stakeForm": {
+ "formBtn": "Add Stake",
+ "skipBtn": "Skip",
+ "nextBtn": "Next",
+ "label": "Stake amount",
+ "description": "Please add bellow the amount to stake",
+ "successAlert": "You have successfully staked {{amount}} HMT",
+ "invalidDecimals": "Incorrect decimal expansion. HMT token has {{decimals}} decimals"
+ },
+ "addKeysPage": {
+ "title": "Setup Operator",
+ "btn": " Add New Keys to KVStore",
+ "skipBtn": "Skip",
+ "pendingKeys": {
+ "title": "Pending Keys",
+ "fee": "Fee",
+ "publicKey": "Public Key",
+ "webhookUrl": "Webhook URL",
+ "role": "Role",
+ "jobType": "Job type"
+ },
+ "existingKeys": {
+ "title": "Existing keys",
+ "fee": "Fee",
+ "publicKey": "Public Key",
+ "url": "Url",
+ "webhookUrl": "Webhook URL",
+ "role": "Role",
+ "jobType": "Job type",
+ "noValue": "no value",
+ "editBtn": "Edit"
+ },
+ "editKeysForm": {
+ "btn": "Save",
+ "error": "No changes"
+ }
+ },
+ "editExistingKeysSuccess": {
+ "title": "Setup Operator",
+ "paragraph1": "Congratulations 🎉!",
+ "paragraph2": "Operator setup is completed, please press the button below to finish sign up.",
+ "btn": "Finish"
+ }
+ },
+ "walletConnectModal": {
+ "header": "Connect Wallet",
+ "paragraph": "The HUMAN App runs on Polygon. Please make sure you enter your Polygon wallet address. <1>Learn more.1>",
+ "connectBtn": "Connect Wallet",
+ "cancelBtn": "Cancel"
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/i18n/i18n.ts b/packages/apps/human-app/frontend/src/i18n/i18n.ts
new file mode 100644
index 0000000000..41812aa5dd
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/i18n/i18n.ts
@@ -0,0 +1,30 @@
+import * as i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+import enTranslation from '@/i18n/en.json';
+
+const resources = {
+ en: {
+ translation: enTranslation,
+ },
+};
+
+declare module 'i18next' {
+ interface CustomTypeOptions {
+ resources: (typeof resources)['en'];
+ }
+}
+
+void i18n
+ .use(initReactI18next) // passes i18n down to react-i18next
+ .init({
+ resources,
+ lng: 'en', // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
+ // you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
+ // if you're using a language detector, do not define the lng option
+
+ interpolation: {
+ escapeValue: false, // react already safes from xss
+ },
+ });
+
+export { i18n };
diff --git a/packages/apps/human-app/frontend/src/main.tsx b/packages/apps/human-app/frontend/src/main.tsx
new file mode 100644
index 0000000000..12bbc63017
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/main.tsx
@@ -0,0 +1,55 @@
+import { StrictMode } from 'react';
+import { createRoot } from 'react-dom/client';
+import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
+import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
+import '@/i18n/i18n';
+import { ThemeProvider, createTheme } from '@mui/material';
+import CssBaseline from '@mui/material/CssBaseline';
+import { BrowserRouter } from 'react-router-dom';
+import { theme } from '@/styles/theme';
+import { DisplayModal } from '@/components/ui/modal/display-modal';
+import { AuthProvider } from '@/auth/auth-context';
+import { Router } from '@/router/router';
+import '@fontsource/inter';
+import '@fontsource/inter/400.css';
+import '@fontsource/inter/500.css';
+import '@fontsource/inter/600.css';
+import '@fontsource/inter/800.css';
+import { WalletConnectProvider } from '@/contexts/wallet-connect';
+import { Web3AuthProvider } from '@/auth-web3/web3-auth-context';
+import { JWTExpirationCheck } from '@/contexts/jwt-expiration-check';
+
+const root = document.getElementById('root');
+if (!root) throw Error('root element is undefined');
+
+const queryClient = new QueryClient({
+ defaultOptions: {
+ mutations: { retry: 0 },
+ queries: { retry: 0 },
+ },
+});
+
+const themes = createTheme(theme);
+
+createRoot(root).render(
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+);
diff --git a/packages/apps/human-app/frontend/src/pages/homepage/components/chat.tsx b/packages/apps/human-app/frontend/src/pages/homepage/components/chat.tsx
new file mode 100644
index 0000000000..2843a778f0
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/homepage/components/chat.tsx
@@ -0,0 +1,80 @@
+import { useEffect, useRef } from 'react';
+
+export function Chat({
+ displayChatIcon = true,
+}: {
+ displayChatIcon?: boolean;
+}) {
+ const ref = useRef(null);
+
+ useEffect(() => {
+ let chatElement: HTMLElement | undefined;
+ const root = document.getElementById('root') as Element | undefined;
+ if (!root) return;
+
+ const positionChatElement = () => {
+ if (chatElement && ref.current) {
+ const refRect = ref.current.getBoundingClientRect();
+ const rootRect = root.getBoundingClientRect();
+
+ chatElement.style.position = 'absolute';
+ if (displayChatIcon) {
+ chatElement.style.opacity = '1';
+ chatElement.style.top = `${refRect.top - rootRect.top}px`;
+ chatElement.style.left = `${refRect.left - rootRect.left}px`;
+ chatElement.style.width = `${refRect.width}px`;
+ chatElement.style.height = `${refRect.height}px`;
+ } else {
+ chatElement.style.opacity = '0';
+ }
+ }
+ };
+
+ const mutationObserver = new MutationObserver((mutationsList) => {
+ for (const mutation of mutationsList) {
+ if (mutation.type === 'childList') {
+ chatElement = document.querySelector('[data-id="zsalesiq"]') as
+ | HTMLElement
+ | undefined;
+ if (chatElement && ref.current) {
+ positionChatElement();
+ }
+ }
+ }
+ });
+
+ mutationObserver.observe(document.body, {
+ childList: true,
+ subtree: true,
+ });
+
+ const resizeObserverElement = document.createElement('div');
+ resizeObserverElement.style.position = 'absolute';
+ resizeObserverElement.style.width = '100%';
+ resizeObserverElement.style.height = '100%';
+ resizeObserverElement.style.top = '0';
+ resizeObserverElement.style.left = '0';
+ resizeObserverElement.style.opacity = '0';
+ resizeObserverElement.style.pointerEvents = 'none';
+ document.body.appendChild(resizeObserverElement);
+
+ const resizeObserver = new ResizeObserver(positionChatElement);
+
+ resizeObserver.observe(resizeObserverElement);
+
+ return () => {
+ resizeObserver.disconnect();
+ mutationObserver.disconnect();
+ if (resizeObserverElement.parentNode) {
+ resizeObserverElement.parentNode.removeChild(resizeObserverElement);
+ }
+ };
+ }, [ref, displayChatIcon]);
+
+ return (
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/homepage/components/choose-sign-up-account-type.tsx b/packages/apps/human-app/frontend/src/pages/homepage/components/choose-sign-up-account-type.tsx
new file mode 100644
index 0000000000..0c3d4b7c8b
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/homepage/components/choose-sign-up-account-type.tsx
@@ -0,0 +1,204 @@
+import {
+ Container,
+ Grid,
+ IconButton,
+ List,
+ ListItemText,
+ Typography,
+} from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+import { BackArrowIcon } from '@/components/ui/icons';
+import { colorPalette } from '@/styles/color-palette';
+import { Button } from '@/components/ui/button';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import type { HomePageStageType } from '@/pages/homepage/components/home-container';
+import { routerPaths } from '@/router/router-paths';
+
+interface ChooseSignUpAccountType {
+ setStage: (step: HomePageStageType) => void;
+}
+
+export function ChooseSignUpAccountType({ setStage }: ChooseSignUpAccountType) {
+ const { t } = useTranslation();
+ const isMobile = useIsMobile('lg');
+
+ const backToWelcomeStage = () => {
+ setStage('welcome');
+ };
+
+ return (
+
+
+ {t('homepage.cancel')}
+
+
+
+
+
+
+ {t('homepage.welcome')} 👋
+
+
+ {t('homepage.howWillUse')}
+
+
+
+ {t('homepage.selectOption')}
+
+
+
+
+
+ {t('homepage.iWantToEarn')}
+
+
+
+
+
+
+
+ {t('homepage.signUpToComplete')}
+
+
+
+
+
+
+ {t('homepage.joinAsOperator')}
+
+
+
+
+
+
+
+ {t('homepage.signAsOperator')}
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/homepage/components/home-container.tsx b/packages/apps/human-app/frontend/src/pages/homepage/components/home-container.tsx
new file mode 100644
index 0000000000..a18e1c827e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/homepage/components/home-container.tsx
@@ -0,0 +1,29 @@
+import { Container } from '@mui/material';
+import { useEffect, useState } from 'react';
+import { useBackgroundColorStore } from '@/hooks/use-background-store';
+import { Welcome } from './welcome';
+import { ChooseSignUpAccountType } from './choose-sign-up-account-type';
+
+export type HomePageStageType = 'welcome' | 'chooseSignUpAccountType';
+
+export function HomeContainer() {
+ const [stage, setStage] = useState('welcome');
+ const { setWhiteBackground, setGrayBackground } = useBackgroundColorStore();
+
+ useEffect(() => {
+ if (stage === 'chooseSignUpAccountType') {
+ setGrayBackground();
+ } else {
+ setWhiteBackground();
+ }
+ }, [setGrayBackground, setWhiteBackground, stage]);
+
+ return (
+
+ {stage === 'welcome' && }
+ {stage === 'chooseSignUpAccountType' && (
+
+ )}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/homepage/components/operator-signin.tsx b/packages/apps/human-app/frontend/src/pages/homepage/components/operator-signin.tsx
new file mode 100644
index 0000000000..baf18e4131
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/homepage/components/operator-signin.tsx
@@ -0,0 +1,94 @@
+import { t } from 'i18next';
+import { useEffect, useRef } from 'react';
+import { Link } from 'react-router-dom';
+import Snackbar from '@mui/material/Snackbar';
+import { Button } from '@/components/ui/button';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+import { useWeb3SignIn } from '@/api/servieces/operator/web3-signin';
+import { useWeb3Auth } from '@/auth-web3/use-web3-auth';
+import { routerPaths } from '@/router/router-paths';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { PrepareSignatureType } from '@/api/servieces/common/prepare-signature';
+
+export function OperatorSignIn() {
+ const { isConnected, openModal, address } = useWalletConnect();
+ const {
+ mutate: signInMutation,
+ isError: isSignInMutationError,
+ error: signInMutationError,
+ } = useWeb3SignIn();
+ const { user, signOut } = useWeb3Auth();
+ const modalWasOpened = useRef(false);
+
+ useEffect(() => {
+ signOut();
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- ...
+ }, []);
+
+ useEffect(() => {
+ if (isConnected && modalWasOpened.current) {
+ signInMutation({ address, type: PrepareSignatureType.SignIn });
+ }
+ }, [address, isConnected, signInMutation]);
+
+ const getSnackBar = () => {
+ return (
+
+ );
+ };
+
+ if (user) {
+ return (
+ <>
+
+ {t('homepage.operatorSignIn')}
+
+ {getSnackBar()}
+ >
+ );
+ }
+
+ if (!isConnected) {
+ return (
+ <>
+ {
+ modalWasOpened.current = true;
+ void openModal();
+ }}
+ size="large"
+ variant="outlined"
+ >
+ {t('homepage.operatorSignIn')}
+
+ {getSnackBar()}
+ >
+ );
+ }
+
+ return (
+ <>
+ {
+ signInMutation({ address, type: PrepareSignatureType.SignIn });
+ }}
+ size="large"
+ variant="outlined"
+ >
+ {t('homepage.operatorSignIn')}
+
+ {getSnackBar()}
+ >
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/homepage/components/welcome.tsx b/packages/apps/human-app/frontend/src/pages/homepage/components/welcome.tsx
new file mode 100644
index 0000000000..595bb747d0
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/homepage/components/welcome.tsx
@@ -0,0 +1,121 @@
+import { Divider, Grid, Paper, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import {
+ HomepageLogoIcon,
+ HomepageUserIcon,
+ HomepageWorkIcon,
+} from '@/components/ui/icons';
+import { Button } from '@/components/ui/button';
+import { colorPalette } from '@/styles/color-palette';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import type { HomePageStageType } from '@/pages/homepage/components/home-container';
+import { OperatorSignIn } from '@/pages/homepage/components/operator-signin';
+import { WorkerSignIn } from '@/pages/homepage/components/worker-signin';
+
+interface WelcomeProps {
+ setStage: (step: HomePageStageType) => void;
+}
+
+export function Welcome({ setStage }: WelcomeProps) {
+ const { t } = useTranslation();
+ const logoText: string = t('homepage.humanApp');
+ const logoTextSplit: string[] = logoText.split(' ');
+ const isMobile = useIsMobile('lg');
+
+ return (
+
+
+
+ {isMobile ? (
+
+
+
+
+
+ ) : (
+
+
+
+
+
+ )}
+
+ {logoTextSplit[0]}
+
+ {logoTextSplit[1]}
+
+
+
+ {t('homepage.completeJobs')}
+
+
+
+
+
+ {
+ setStage('chooseSignUpAccountType');
+ }}
+ size="large"
+ sx={{
+ backgroundColor: colorPalette.primary.light,
+ mb: '1.5625rem',
+ }}
+ variant="contained"
+ >
+ {t('homepage.signUp')}
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/homepage/components/worker-signin.tsx b/packages/apps/human-app/frontend/src/pages/homepage/components/worker-signin.tsx
new file mode 100644
index 0000000000..1bf95ace9a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/homepage/components/worker-signin.tsx
@@ -0,0 +1,21 @@
+import { t } from 'i18next';
+import { Link } from 'react-router-dom';
+import { Button } from '@/components/ui/button';
+import { routerPaths } from '@/router/router-paths';
+
+export function WorkerSignIn() {
+ return (
+
+ {t('homepage.workerSignIn')}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/homepage/home.page.tsx b/packages/apps/human-app/frontend/src/pages/homepage/home.page.tsx
new file mode 100644
index 0000000000..0408873f72
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/homepage/home.page.tsx
@@ -0,0 +1,26 @@
+import Box from '@mui/material/Box';
+import { Paper } from '@mui/material';
+import { colorPalette } from '@/styles/color-palette';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { HomeContainer } from './components/home-container';
+
+export function HomePage() {
+ const isMobile = useIsMobile();
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/profile/profile-disable-button.tsx b/packages/apps/human-app/frontend/src/pages/operator/profile/profile-disable-button.tsx
new file mode 100644
index 0000000000..416efe69e8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/profile/profile-disable-button.tsx
@@ -0,0 +1,53 @@
+import { t } from 'i18next';
+import { Typography } from '@mui/material';
+import { useDisableWeb3Operator } from '@/api/servieces/operator/disable-operator';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { Button } from '@/components/ui/button';
+import type { SignatureData } from '@/api/servieces/common/prepare-signature';
+import {
+ PrepareSignatureType,
+ usePrepareSignature,
+} from '@/api/servieces/common/prepare-signature';
+
+export function ProfileDisableButton() {
+ const { address, signMessage } = useConnectedWallet();
+ const {
+ data: signatureData,
+ isError: isSignatureDataError,
+ isPending: isSignatureDataPending,
+ } = usePrepareSignature({
+ address,
+ type: PrepareSignatureType.DisableOperator,
+ });
+
+ const {
+ mutate: disableOperatorMutation,
+ isError: isDisableOperatorError,
+ isPaused: isDisableOperatorPending,
+ } = useDisableWeb3Operator();
+
+ const disableOperator = async (signaturePayload: SignatureData) => {
+ const signature = await signMessage(JSON.stringify(signaturePayload));
+ disableOperatorMutation({ signature: signature || '' });
+ };
+
+ if (isSignatureDataError || isDisableOperatorError) {
+ return (
+ {t('operator.profile.disable.cannotDisable')}
+ );
+ }
+
+ return (
+ {
+ if (signatureData) {
+ void disableOperator(signatureData);
+ }
+ }}
+ variant="contained"
+ >
+ {t('operator.profile.disable.disableBtn')}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/profile/profile-enable-button.tsx b/packages/apps/human-app/frontend/src/pages/operator/profile/profile-enable-button.tsx
new file mode 100644
index 0000000000..8024ba1331
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/profile/profile-enable-button.tsx
@@ -0,0 +1,11 @@
+import { t } from 'i18next';
+import { Button } from '@/components/ui/button';
+
+export function ProfileEnableButton() {
+ // TODO add operator activation
+ return (
+
+ {t('operator.profile.activateBtn')}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/profile/profile.page.tsx b/packages/apps/human-app/frontend/src/pages/operator/profile/profile.page.tsx
new file mode 100644
index 0000000000..c578efed32
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/profile/profile.page.tsx
@@ -0,0 +1,231 @@
+import { useEffect } from 'react';
+import { Grid, List, Paper, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { useBackgroundColorStore } from '@/hooks/use-background-store';
+import { colorPalette } from '@/styles/color-palette';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { useGetKeys } from '@/api/servieces/operator/get-keys';
+import { useWeb3AuthenticatedUser } from '@/auth-web3/use-web3-authenticated-user';
+import { PageCardError, PageCardLoader } from '@/components/ui/page-card';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { ProfileDisableButton } from '@/pages/operator/profile/profile-disable-button';
+import { ProfileListItem } from '@/components/ui/profile-list-item';
+import { useGetOperatorStats } from '@/api/servieces/operator/get-stats';
+import { ProfileEnableButton } from '@/pages/operator/profile/profile-enable-button';
+import { CheckmarkIcon, LockerIcon } from '@/components/ui/icons';
+
+export function OperatorProfilePage() {
+ const { setGrayBackground } = useBackgroundColorStore();
+ const { t } = useTranslation();
+ const isMobile = useIsMobile('lg');
+ const { user } = useWeb3AuthenticatedUser();
+ const {
+ data: keysData,
+ error: keysError,
+ isError: isKeysError,
+ isPending: isKeysDataPending,
+ } = useGetKeys();
+
+ const {
+ data: statsData,
+ error: statsError,
+ isError: isStatsError,
+ isPending: isStatsPending,
+ refetch: refetchStats,
+ } = useGetOperatorStats();
+
+ const isOperatorActive = user.status === 'ACTIVE';
+
+ useEffect(() => {
+ setGrayBackground();
+ }, [setGrayBackground]);
+
+ useEffect(() => {
+ if (keysData?.url) {
+ void refetchStats();
+ }
+ }, [keysData?.url, refetchStats]);
+
+ if (isKeysDataPending || isStatsPending) {
+ return ;
+ }
+
+ if (isKeysError || isStatsError) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
+ {t('operator.profile.about.header')}
+
+
+
+
+
+
+ {t('operator.profile.about.status.statusHeader')}
+
+ {isOperatorActive ? (
+
+ {t('operator.profile.about.status.statusActivated')}
+
+
+ ) : (
+
+ {t('operator.profile.about.status.statusDeactivated')}
+
+
+ )}
+
+ {isOperatorActive ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t('operator.profile.statistics.header')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/add-keys.page.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/add-keys.page.tsx
new file mode 100644
index 0000000000..f290dcf886
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/add-keys.page.tsx
@@ -0,0 +1,95 @@
+import { Grid } from '@mui/material';
+import type { UseFormReturn } from 'react-hook-form';
+import { t } from 'i18next';
+import { Link } from 'react-router-dom';
+import {
+ PageCard,
+ PageCardError,
+ PageCardLoader,
+} from '@/components/ui/page-card';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { Alert } from '@/components/ui/alert';
+import type { EditEthKVStoreValuesMutationData } from '@/api/servieces/operator/edit-existing-keys';
+import { useEditExistingKeysMutationState } from '@/api/servieces/operator/edit-existing-keys';
+import type { GetEthKVStoreValuesSuccessResponse } from '@/api/servieces/operator/get-keys';
+import { useGetKeys } from '@/api/servieces/operator/get-keys';
+import { jsonRpcErrorHandler } from '@/shared/helpers/json-rpc-error-handler';
+import { ExistingKeysForm } from '@/pages/operator/sign-up/add-keys/existing-keys-form';
+import { PendingKeysForm } from '@/pages/operator/sign-up/add-keys/pending-keys-form';
+import { Button } from '@/components/ui/button';
+import { routerPaths } from '@/router/router-paths';
+
+export type UseFormResult = UseFormReturn<
+ GetEthKVStoreValuesSuccessResponse,
+ EditEthKVStoreValuesMutationData
+>;
+
+export function AddKeysOperatorPage() {
+ const {
+ data: keysData,
+ isError: isGetKeysError,
+ error: getKeysError,
+ isPending: isGetKeysPending,
+ } = useGetKeys();
+ const editExistingKeysMutationState = useEditExistingKeysMutationState();
+
+ const errorAlert = editExistingKeysMutationState?.error ? (
+
+ {defaultErrorMessage(
+ editExistingKeysMutationState.error,
+ jsonRpcErrorHandler
+ )}
+
+ ) : undefined;
+
+ if (isGetKeysError) {
+ return ;
+ }
+
+ if (isGetKeysPending) {
+ return ;
+ }
+
+ return (
+
+
+
+ );
+}
+
+export function Form({
+ keysData,
+}: {
+ keysData: GetEthKVStoreValuesSuccessResponse;
+}) {
+ const areSomeExistingKeys = Object.values(keysData).filter(Boolean).length;
+ const areSomePendingKeys = Object.entries(keysData).filter(
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- it's necessary
+ ([key, values]) => key && !values?.length
+ ).length;
+
+ return (
+
+
+ {areSomeExistingKeys ?
: null}
+ {areSomePendingKeys ?
: null}
+ {areSomeExistingKeys && !areSomePendingKeys ? (
+
+ {t('operator.addKeysPage.skipBtn')}
+
+ ) : null}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-existing-keys-form.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-existing-keys-form.tsx
new file mode 100644
index 0000000000..4a9d4ab733
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-existing-keys-form.tsx
@@ -0,0 +1,124 @@
+import { Grid, Typography } from '@mui/material';
+import { t } from 'i18next';
+import { useFormState } from 'react-hook-form';
+import type { CustomButtonProps } from '@/components/ui/button';
+import { Button } from '@/components/ui/button';
+import { colorPalette } from '@/styles/color-palette';
+import { Input } from '@/components/data-entry/input';
+import type { EthKVStoreKeyValues } from '@/smart-contracts/EthKVStore/config';
+import { EthKVStoreKeys, Role } from '@/smart-contracts/EthKVStore/config';
+import { Select } from '@/components/data-entry/select';
+import { MultiSelect } from '@/components/data-entry/multi-select';
+import { JOB_TYPES } from '@/shared/consts';
+import type { GetEthKVStoreValuesSuccessResponse } from '@/api/servieces/operator/get-keys';
+import {
+ order,
+ sortFormKeys,
+} from '@/pages/operator/sign-up/add-keys/sort-form';
+
+const OPTIONS = [Role.ExchangeOracle, Role.JobLauncher, Role.RecordingOracle];
+
+const formInputsConfig: Record = {
+ [EthKVStoreKeys.Fee]: (
+
+ ),
+ [EthKVStoreKeys.PublicKey]: (
+
+ ),
+ [EthKVStoreKeys.Url]: (
+
+ ),
+ [EthKVStoreKeys.WebhookUrl]: (
+
+ ),
+ [EthKVStoreKeys.Role]: (
+ ({
+ name: role,
+ value: role,
+ id: i,
+ }))}
+ />
+ ),
+ [EthKVStoreKeys.JobTypes]: (
+
+ ),
+};
+export function EditExistingKeysForm({
+ existingKeysInitialState,
+ formButtonProps,
+}: {
+ existingKeysInitialState: GetEthKVStoreValuesSuccessResponse;
+ formButtonProps: CustomButtonProps;
+}) {
+ const { errors } = useFormState();
+ const noChangesError = errors.form?.message as string;
+
+ const sortedKeys = sortFormKeys(
+ Object.keys(existingKeysInitialState) as EthKVStoreKeyValues[],
+ order
+ );
+
+ return (
+
+
+ {t('operator.addKeysPage.existingKeys.title')}
+
+
+ {sortedKeys.map((key) => {
+ const formInputsConfigKey = key as EthKVStoreKeyValues;
+ return (
+ <>
+ {existingKeysInitialState[formInputsConfigKey]
+ ? formInputsConfig[formInputsConfigKey]
+ : null}
+ >
+ );
+ })}
+
+ {noChangesError ? (
+
+
+ {noChangesError}
+
+
+ ) : null}
+
+
+
+ {t('operator.addKeysPage.editKeysForm.btn')}
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-existing-keys-success.page.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-existing-keys-success.page.tsx
new file mode 100644
index 0000000000..2f65b814bb
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-existing-keys-success.page.tsx
@@ -0,0 +1,89 @@
+import { t } from 'i18next';
+import { Grid, Typography } from '@mui/material';
+import {
+ PageCard,
+ PageCardError,
+ PageCardLoader,
+} from '@/components/ui/page-card';
+import { Button } from '@/components/ui/button';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { useWeb3SignUp } from '@/api/servieces/operator/web3-signup';
+import { Alert } from '@/components/ui/alert';
+import type { SignatureData } from '@/api/servieces/common/prepare-signature';
+import {
+ PrepareSignatureType,
+ usePrepareSignature,
+} from '@/api/servieces/common/prepare-signature';
+
+export function EditExistingKeysSuccessPage() {
+ const { address, signMessage } = useConnectedWallet();
+ const {
+ data: signatureData,
+ isError: isSignatureDataError,
+ error: errorSignatureDataError,
+ isPending: isSignatureDataPending,
+ } = usePrepareSignature({
+ address,
+ type: PrepareSignatureType.SignUp,
+ });
+
+ const {
+ mutate: web3SignUpMutation,
+ isError: isWeb3SignUpError,
+ error: web3SignUpError,
+ isPending: web3SignUpPending,
+ } = useWeb3SignUp();
+
+ const createSignature = async (data: SignatureData) => {
+ const signature = await signMessage(JSON.stringify(data));
+ web3SignUpMutation({ signature: signature || '' });
+ };
+
+ if (isSignatureDataError) {
+ return (
+
+ );
+ }
+
+ if (isSignatureDataPending) {
+ return ;
+ }
+
+ return (
+
+ {defaultErrorMessage(web3SignUpError)}
+
+ ) : undefined
+ }
+ hiddenCancelButton
+ title={t('operator.editExistingKeysSuccess.title')}
+ >
+
+
+
+ {t('operator.editExistingKeysSuccess.paragraph1')}
+
+
+ {t('operator.editExistingKeysSuccess.paragraph2')}
+
+
+ {
+ void createSignature(signatureData);
+ }}
+ variant="contained"
+ >
+ {t('operator.editExistingKeysSuccess.btn')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-pending-keys-form.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-pending-keys-form.tsx
new file mode 100644
index 0000000000..b42c3c6412
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/edit-pending-keys-form.tsx
@@ -0,0 +1,97 @@
+import { Grid, Typography } from '@mui/material';
+import { t } from 'i18next';
+import { Input } from '@/components/data-entry/input';
+import type { EthKVStoreKeyValues } from '@/smart-contracts/EthKVStore/config';
+import { EthKVStoreKeys, Role } from '@/smart-contracts/EthKVStore/config';
+import { Select } from '@/components/data-entry/select';
+import { MultiSelect } from '@/components/data-entry/multi-select';
+import { JOB_TYPES } from '@/shared/consts';
+import type { GetEthKVStoreValuesSuccessResponse } from '@/api/servieces/operator/get-keys';
+import {
+ order,
+ sortFormKeys,
+} from '@/pages/operator/sign-up/add-keys/sort-form';
+
+const OPTIONS = [Role.ExchangeOracle, Role.JobLauncher, Role.RecordingOracle];
+
+const formInputsConfig: Record = {
+ [EthKVStoreKeys.Fee]: (
+
+ ),
+ [EthKVStoreKeys.PublicKey]: (
+
+ ),
+ [EthKVStoreKeys.Url]: (
+
+ ),
+ [EthKVStoreKeys.WebhookUrl]: (
+
+ ),
+ [EthKVStoreKeys.Role]: (
+ ({
+ name: role,
+ value: role,
+ id: i,
+ }))}
+ />
+ ),
+ [EthKVStoreKeys.JobTypes]: (
+
+ ),
+};
+
+export function EditPendingKeysForm({
+ existingKeysInitialState,
+}: {
+ existingKeysInitialState: GetEthKVStoreValuesSuccessResponse;
+}) {
+ const sortedKeys = sortFormKeys(
+ Object.keys(existingKeysInitialState) as EthKVStoreKeyValues[],
+ order
+ );
+
+ return (
+
+
+ {t('operator.addKeysPage.pendingKeys.title')}
+
+
+ {sortedKeys.map((key) => {
+ const formInputsConfigKey = key as EthKVStoreKeyValues;
+ return (
+ <>
+ {!existingKeysInitialState[formInputsConfigKey]
+ ? formInputsConfig[formInputsConfigKey]
+ : null}
+ >
+ );
+ })}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/existing-keys-form.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/existing-keys-form.tsx
new file mode 100644
index 0000000000..ae8fd3f5a2
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/existing-keys-form.tsx
@@ -0,0 +1,88 @@
+import { useState } from 'react';
+import { Grid } from '@mui/material';
+import { zodResolver } from '@hookform/resolvers/zod';
+import type { UseFormReturn } from 'react-hook-form';
+import { FormProvider, useForm } from 'react-hook-form';
+import type { EditEthKVStoreValuesMutationData } from '@/api/servieces/operator/edit-existing-keys';
+import {
+ getEditEthKVStoreValuesMutationSchema,
+ useEditExistingKeysMutation,
+} from '@/api/servieces/operator/edit-existing-keys';
+import { ExistingKeys } from '@/pages/operator/sign-up/add-keys/existing-keys';
+import { EditExistingKeysForm } from '@/pages/operator/sign-up/add-keys/edit-existing-keys-form';
+import type { GetEthKVStoreValuesSuccessResponse } from '@/api/servieces/operator/get-keys';
+
+export type UseFormResult = UseFormReturn<
+ GetEthKVStoreValuesSuccessResponse,
+ EditEthKVStoreValuesMutationData
+>;
+
+export function ExistingKeysForm({
+ keysData,
+}: {
+ keysData: GetEthKVStoreValuesSuccessResponse;
+}) {
+ const [editMode, setEditMode] = useState(false);
+ const existingKeysMutation = useEditExistingKeysMutation();
+ const pendingKeysMutation = useEditExistingKeysMutation();
+ const existingKeysMethods = useForm<
+ GetEthKVStoreValuesSuccessResponse,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- automatic inferring
+ any,
+ EditEthKVStoreValuesMutationData
+ >({
+ defaultValues: keysData,
+ resolver: zodResolver(getEditEthKVStoreValuesMutationSchema(keysData)),
+ });
+
+ const handleEditExistingKeys = (data: EditEthKVStoreValuesMutationData) => {
+ existingKeysMutation.mutate(data);
+ };
+
+ return (
+
+
+
+ {...existingKeysMethods}
+ >
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/existing-keys.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/existing-keys.tsx
new file mode 100644
index 0000000000..b0d60da490
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/existing-keys.tsx
@@ -0,0 +1,122 @@
+/* eslint-disable camelcase -- ....*/
+import { Grid, Typography } from '@mui/material';
+import { t } from 'i18next';
+import ModeEditIcon from '@mui/icons-material/ModeEdit';
+import { useFormContext } from 'react-hook-form';
+import { Button } from '@/components/ui/button';
+import { colorPalette } from '@/styles/color-palette';
+import type { EthKVStoreKeyValues } from '@/smart-contracts/EthKVStore/config';
+import { EthKVStoreKeys } from '@/smart-contracts/EthKVStore/config';
+import { OptionalText } from '@/components/ui/optional-text';
+import { EmptyPlaceholder } from '@/components/ui/empty-placeholder';
+import type { GetEthKVStoreValuesSuccessResponse } from '@/api/servieces/operator/get-keys';
+import { Chips } from '@/components/ui/chips';
+import { Chip } from '@/components/ui/chip';
+import {
+ order,
+ sortFormKeys,
+} from '@/pages/operator/sign-up/add-keys/sort-form';
+
+const existingKeysConfig: Record<
+ EthKVStoreKeyValues,
+ (values: GetEthKVStoreValuesSuccessResponse) => React.ReactElement
+> = {
+ [EthKVStoreKeys.Fee]: ({ fee }) => (
+
+
+ {t('operator.addKeysPage.existingKeys.fee')}
+
+
+
+
+
+ ),
+ [EthKVStoreKeys.PublicKey]: ({ public_key }) => (
+
+
+ {t('operator.addKeysPage.existingKeys.publicKey')}
+
+
+
+
+
+ ),
+ [EthKVStoreKeys.Url]: ({ url }) => (
+
+
+ {t('operator.addKeysPage.existingKeys.url')}
+
+
+
+
+
+ ),
+ [EthKVStoreKeys.WebhookUrl]: ({ webhook_url }) => (
+
+
+ {t('operator.addKeysPage.existingKeys.webhookUrl')}
+
+
+
+
+
+ ),
+ [EthKVStoreKeys.Role]: ({ role }) => (
+
+
+ {t('operator.addKeysPage.existingKeys.role')}
+
+ {role ? : }
+
+ ),
+ [EthKVStoreKeys.JobTypes]: ({ job_types }) => (
+
+
+ {t('operator.addKeysPage.existingKeys.jobType')}
+
+ {job_types ? : }
+
+ ),
+};
+
+export function ExistingKeys({
+ openEditMode,
+ existingKeysInitialState,
+}: {
+ openEditMode: () => void;
+ existingKeysInitialState: GetEthKVStoreValuesSuccessResponse;
+}) {
+ const { getValues } = useFormContext();
+ const formValues = getValues();
+
+ const sortedKeys = sortFormKeys(
+ Object.keys(existingKeysInitialState) as EthKVStoreKeyValues[],
+ order
+ );
+
+ return (
+
+
+ {t('operator.addKeysPage.existingKeys.title')}
+
+ {sortedKeys.map((key) => {
+ const existingKeysConfigKey = key as EthKVStoreKeyValues;
+ return existingKeysInitialState[existingKeysConfigKey]
+ ? existingKeysConfig[existingKeysConfigKey](formValues)
+ : null;
+ })}
+
+ }
+ variant="contained"
+ >
+
+ {t('operator.addKeysPage.existingKeys.editBtn')}
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/pending-keys-form.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/pending-keys-form.tsx
new file mode 100644
index 0000000000..204a5256b6
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/pending-keys-form.tsx
@@ -0,0 +1,66 @@
+import { t } from 'i18next';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { FormProvider, useForm } from 'react-hook-form';
+import type { EditEthKVStoreValuesMutationData } from '@/api/servieces/operator/edit-existing-keys';
+import {
+ editEthKVStoreValuesMutationSchema,
+ useEditExistingKeysMutation,
+} from '@/api/servieces/operator/edit-existing-keys';
+import { Button } from '@/components/ui/button';
+import { EditPendingKeysForm } from '@/pages/operator/sign-up/add-keys/edit-pending-keys-form';
+import type { GetEthKVStoreValuesSuccessResponse } from '@/api/servieces/operator/get-keys';
+
+export function PendingKeysForm({
+ keysData,
+}: {
+ keysData: GetEthKVStoreValuesSuccessResponse;
+}) {
+ const pendingKeysMutation = useEditExistingKeysMutation();
+
+ const pendingKeysMethods = useForm<
+ GetEthKVStoreValuesSuccessResponse,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- automatic inferring
+ any,
+ EditEthKVStoreValuesMutationData
+ >({
+ defaultValues: {},
+ resolver: zodResolver(editEthKVStoreValuesMutationSchema),
+ });
+
+ const handleEditPendingKey = (data: EditEthKVStoreValuesMutationData) => {
+ pendingKeysMutation.mutate(data);
+ };
+
+ return (
+
+ {...pendingKeysMethods}
+ >
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/sort-form.ts b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/sort-form.ts
new file mode 100644
index 0000000000..f769d14ba0
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-keys/sort-form.ts
@@ -0,0 +1,17 @@
+import type { EthKVStoreKeyValues } from '@/smart-contracts/EthKVStore/config';
+import { EthKVStoreKeys } from '@/smart-contracts/EthKVStore/config';
+
+export const sortFormKeys = (
+ keys: EthKVStoreKeyValues[],
+ order: EthKVStoreKeyValues[]
+): EthKVStoreKeyValues[] => {
+ return keys.sort((a, b) => order.indexOf(a) - order.indexOf(b));
+};
+export const order: EthKVStoreKeyValues[] = [
+ EthKVStoreKeys.Fee,
+ EthKVStoreKeys.PublicKey,
+ EthKVStoreKeys.Url,
+ EthKVStoreKeys.WebhookUrl,
+ EthKVStoreKeys.Role,
+ EthKVStoreKeys.JobTypes,
+];
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/add-stake.page.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/add-stake.page.tsx
new file mode 100644
index 0000000000..f960ef742a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/add-stake.page.tsx
@@ -0,0 +1,103 @@
+import Grid from '@mui/material/Grid';
+import { Typography } from '@mui/material';
+import { useState } from 'react';
+import { t } from 'i18next';
+import {
+ PageCard,
+ PageCardError,
+ PageCardLoader,
+} from '@/components/ui/page-card';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { colorPalette } from '@/styles/color-palette';
+import { Buttons } from '@/pages/operator/sign-up/add-stake/buttons';
+import { StakeForm } from '@/pages/operator/sign-up/add-stake/stake-form';
+import { Alert } from '@/components/ui/alert';
+import {
+ stakedAmountFormatter,
+ useGetStakedAmount,
+} from '@/api/servieces/operator/get-stacked-amount';
+import { useAddStakeMutationState } from '@/api/servieces/operator/add-stake';
+import { useHMTokenDecimals } from '@/api/servieces/operator/human-token-decimals';
+
+export function AddStakeOperatorPage() {
+ const [displayForm, setDisplayForm] = useState(false);
+ const {
+ data: stakedAmount,
+ isError: isGetStakedAmountError,
+ error: getStackedAmountError,
+ isPending: isGetStakedAmountPending,
+ } = useGetStakedAmount();
+ const addStakeMutationState = useAddStakeMutationState();
+ const {
+ data: decimalsData,
+ error: decimalsDataError,
+ isPending: isDecimalsDataPending,
+ } = useHMTokenDecimals();
+
+ const getAlert = () => {
+ switch (true) {
+ case Boolean(addStakeMutationState?.error):
+ return (
+
+ {defaultErrorMessage(addStakeMutationState?.error)}
+
+ );
+ case addStakeMutationState?.status === 'success':
+ return (
+
+ {t('operator.stakeForm.successAlert', {
+ amount: addStakeMutationState.variables?.amount
+ ? addStakeMutationState.variables.amount
+ : -1,
+ })}
+
+ );
+
+ default:
+ return undefined;
+ }
+ };
+
+ if (isGetStakedAmountError || decimalsDataError) {
+ return (
+
+ );
+ }
+
+ if (
+ isGetStakedAmountPending ||
+ isDecimalsDataPending ||
+ decimalsData === undefined
+ ) {
+ return ;
+ }
+
+ return (
+
+
+
+ {t('operator.addStake.formHeader')}
+
+
+ {t('operator.addStake.label')}
+
+
+ {stakedAmountFormatter(stakedAmount)}
+
+ {displayForm ? (
+
+ ) : (
+
+ )}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/buttons.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/buttons.tsx
new file mode 100644
index 0000000000..f6ac0b57bd
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/buttons.tsx
@@ -0,0 +1,49 @@
+import Button from '@mui/material/Button';
+import Grid from '@mui/material/Grid';
+import { t } from 'i18next';
+import { Link } from 'react-router-dom';
+import { breakpoints } from '@/styles/theme';
+import { routerPaths } from '@/router/router-paths';
+
+export function Buttons({
+ openForm,
+ stakedAmount,
+}: {
+ openForm: () => void;
+ stakedAmount?: bigint;
+}) {
+ const isStaked = stakedAmount ? stakedAmount > BigInt(0) : false;
+ return (
+
+ {
+ openForm();
+ }}
+ variant="contained"
+ >
+ {t('operator.addStake.actionBtn')}
+
+
+ {isStaked
+ ? t('operator.addStake.nextBtn')
+ : t('operator.addStake.skipBtn')}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/stake-form.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/stake-form.tsx
new file mode 100644
index 0000000000..d8d6eb964f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/add-stake/stake-form.tsx
@@ -0,0 +1,97 @@
+import { zodResolver } from '@hookform/resolvers/zod';
+import Grid from '@mui/material/Grid';
+import { FormProvider, useForm } from 'react-hook-form';
+import { t } from 'i18next';
+import { Link } from 'react-router-dom';
+import { Typography } from '@mui/material';
+import { z } from 'zod';
+import {
+ addStakeAmountCallArgumentsSchema,
+ useAddStakeMutation,
+ type AddStakeCallArguments,
+} from '@/api/servieces/operator/add-stake';
+import { breakpoints } from '@/styles/theme';
+import { Input } from '@/components/data-entry/input';
+import { routerPaths } from '@/router/router-paths';
+import { Button } from '@/components/ui/button';
+
+export function StakeForm({
+ decimals,
+ stakedAmount,
+}: {
+ decimals: number;
+ stakedAmount?: bigint;
+}) {
+ const addStakeMutation = useAddStakeMutation();
+
+ const methods = useForm({
+ defaultValues: {
+ // Since we deal with numbers that may have huge decimal extensions,
+ // we are using strings as a safer solution
+ amount: '0',
+ },
+ resolver: zodResolver(
+ z.object({ amount: addStakeAmountCallArgumentsSchema(decimals) })
+ ),
+ });
+
+ const addStake = (data: AddStakeCallArguments) => {
+ addStakeMutation.mutate(data);
+ };
+
+ const isStaked = stakedAmount ? stakedAmount > BigInt(0) : false;
+ return (
+
+
+ {t('operator.stakeForm.description')}
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/connect-wallet.page.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/connect-wallet.page.tsx
new file mode 100644
index 0000000000..abcf28e1d5
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/connect-wallet.page.tsx
@@ -0,0 +1,64 @@
+import { Grid, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { Navigate } from 'react-router-dom';
+import { PageCard } from '@/components/ui/page-card';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+import { Alert } from '@/components/ui/alert';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { Button } from '@/components/ui/button';
+import { useModalStore } from '@/components/ui/modal/modal.store';
+import { routerPaths } from '@/router/router-paths';
+
+export function ConnectWalletOperatorPage() {
+ const { t } = useTranslation();
+ const { openModal } = useModalStore();
+ const {
+ isConnected,
+ web3ProviderMutation: {
+ error: web3ProviderError,
+ status: web3ProviderStatus,
+ },
+ } = useWalletConnect();
+
+ const getAlert = () => {
+ switch (true) {
+ case web3ProviderStatus === 'error':
+ return (
+
+ {defaultErrorMessage(web3ProviderError)}
+
+ );
+ case isConnected:
+ return (
+
+ {t('operator.connectWallet.successAlert')}
+
+ );
+
+ default:
+ return undefined;
+ }
+ };
+
+ if (isConnected) {
+ return ;
+ }
+
+ return (
+
+
+
+ {t('operator.connectWallet.description')}
+
+ {
+ openModal('WALLET_CONNECT');
+ }}
+ variant="contained"
+ >
+ {t('components.wallet.connectBtn.connect')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/operator/sign-up/set-up-operator.tsx b/packages/apps/human-app/frontend/src/pages/operator/sign-up/set-up-operator.tsx
new file mode 100644
index 0000000000..5e0b8ebbf8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/operator/sign-up/set-up-operator.tsx
@@ -0,0 +1,36 @@
+import { Grid, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+import { PageCard } from '@/components/ui/page-card';
+import { Alert } from '@/components/ui/alert';
+import { Button } from '@/components/ui/button';
+import { routerPaths } from '@/router/router-paths';
+import { useConnectedWallet } from '@/auth-web3/use-connected-wallet';
+
+export function SetUpOperatorPage() {
+ const { t } = useTranslation();
+ useConnectedWallet();
+ return (
+
+ {t('operator.connectWallet.successAlert')}
+
+ }
+ title={t('operator.connectWallet.title')}
+ >
+
+
+ {t('operator.connectWallet.description')}
+
+
+ {t('operator.connectWallet.setupOperator')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/playground/modal-example/modal-example.tsx b/packages/apps/human-app/frontend/src/pages/playground/modal-example/modal-example.tsx
new file mode 100644
index 0000000000..d9b083df9a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/playground/modal-example/modal-example.tsx
@@ -0,0 +1,24 @@
+import { Stack } from '@mui/material';
+import Typography from '@mui/material/Typography';
+
+export function ModalExample() {
+ return (
+
+
+ Example Modal
+
+ Lorem ipsum dolor sit amet consectetur, adipisicing elit. Laborum
+ adipisci minima libero voluptates molestiae eligendi fugiat quas,
+ animi labore, perspiciatis quasi deleniti natus numquam laudantium
+ debitis, officia nostrum ad dolore!
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/playground/playground.page.tsx b/packages/apps/human-app/frontend/src/pages/playground/playground.page.tsx
new file mode 100644
index 0000000000..f491614513
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/playground/playground.page.tsx
@@ -0,0 +1,16 @@
+import Paper from '@mui/material/Paper';
+import { FormExample } from '@/components/data-entry/form-example';
+import { UiExample } from '@/components/ui/ui-example';
+
+export function Playground() {
+ return (
+
+
+ Form
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/playground/table-example/table-example.tsx b/packages/apps/human-app/frontend/src/pages/playground/table-example/table-example.tsx
new file mode 100644
index 0000000000..3aac411d1b
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/playground/table-example/table-example.tsx
@@ -0,0 +1,10 @@
+import { TableQueryContextProvider } from '@/components/ui/table/table-query-context';
+import { Table } from '@/pages/playground/table-example/table';
+
+export function TableExample() {
+ return (
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/playground/table-example/table-search-form.tsx b/packages/apps/human-app/frontend/src/pages/playground/table-example/table-search-form.tsx
new file mode 100644
index 0000000000..c8e788b150
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/playground/table-example/table-search-form.tsx
@@ -0,0 +1,55 @@
+import Search from '@mui/icons-material/Search';
+import InputAdornment from '@mui/material/InputAdornment';
+import { FormProvider, useForm } from 'react-hook-form';
+import { Input } from '@/components/data-entry/input';
+import { colorPalette } from '@/styles/color-palette';
+
+interface SearchFormProps {
+ label: string;
+ name: string;
+ placeholder: string;
+ columnId: string;
+ fullWidth?: boolean;
+ updater?: (fieldValue: string) => void;
+}
+
+export function SearchForm({
+ label,
+ name,
+ placeholder,
+ updater,
+ fullWidth = false,
+}: SearchFormProps) {
+ const methods = useForm<{ searchValue: string }>({
+ defaultValues: {
+ searchValue: '',
+ },
+ });
+
+ return (
+
+
+
+
+ ),
+ }}
+ label={label}
+ name={name}
+ onChange={(e) => {
+ if (updater) {
+ updater(e.target.value);
+ }
+ }}
+ placeholder={placeholder}
+ sx={{
+ width: fullWidth ? '100%' : '15rem',
+ margin: fullWidth ? '0' : '1rem',
+ }}
+ />
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/playground/table-example/table-service.tsx b/packages/apps/human-app/frontend/src/pages/playground/table-example/table-service.tsx
new file mode 100644
index 0000000000..b5204d5ea6
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/playground/table-example/table-service.tsx
@@ -0,0 +1,61 @@
+export interface Person {
+ name: {
+ firstName: string;
+ lastName: string;
+ };
+ address: string;
+ city: string;
+ state: string;
+}
+
+const data: Person[] = [
+ {
+ name: {
+ firstName: 'John',
+ lastName: 'Doe',
+ },
+ address: '261 Erdman Ford',
+ city: 'East Daphne',
+ state: 'Kentucky',
+ },
+ {
+ name: {
+ firstName: 'Jane',
+ lastName: 'Doe',
+ },
+ address: '769 Dominic Grove',
+ city: 'Columbus',
+ state: 'Ohio',
+ },
+ {
+ name: {
+ firstName: 'Joe',
+ lastName: 'Doe',
+ },
+ address: '566 Brakus Inlet',
+ city: 'South Linda',
+ state: 'West Virginia',
+ },
+ {
+ name: {
+ firstName: 'Kevin',
+ lastName: 'Vandy',
+ },
+ address: '722 Emie Stream',
+ city: 'Lincoln',
+ state: 'Nebraska',
+ },
+ {
+ name: {
+ firstName: 'Joshua',
+ lastName: 'Rolluffs',
+ },
+ address: '32188 Larkin Turnpike',
+ city: 'Omaha',
+ state: 'Nebraska',
+ },
+];
+
+export function getTableData(): Promise {
+ return Promise.resolve(data);
+}
diff --git a/packages/apps/human-app/frontend/src/pages/playground/table-example/table.tsx b/packages/apps/human-app/frontend/src/pages/playground/table-example/table.tsx
new file mode 100644
index 0000000000..26e4446f58
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/playground/table-example/table.tsx
@@ -0,0 +1,107 @@
+import {
+ MaterialReactTable,
+ useMaterialReactTable,
+ type MRT_ColumnDef,
+} from 'material-react-table';
+import { useQuery } from '@tanstack/react-query';
+import { TableHeaderCell } from '@/components/ui/table/table-header-cell';
+import { useTableQuery } from '@/components/ui/table/table-query-hook';
+import type { Person } from '@/pages/playground/table-example/table-service';
+import { getTableData } from '@/pages/playground/table-example/table-service';
+import { SearchForm } from '@/pages/playground/table-example/table-search-form';
+import { Sorting } from '@/components/ui/table/table-header-menu.tsx/sorting';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+
+const columns: MRT_ColumnDef[] = [
+ {
+ accessorKey: 'name.firstName',
+ header: 'First Name',
+ size: 150,
+ enableSorting: true,
+ },
+ {
+ accessorKey: 'name.lastName',
+ header: 'Last Name',
+ size: 150,
+ muiTableHeadCellProps: () => ({
+ component: (props) => (
+ undefined}
+ sortingOptions={[
+ { label: 'test1', sortCallback: () => undefined },
+ { label: 'test2', sortCallback: () => undefined },
+ ]}
+ />
+ }
+ />
+ ),
+ }),
+ },
+ {
+ accessorKey: 'address',
+ header: 'Address',
+ size: 200,
+ muiTableHeadCellProps: () => ({
+ component: (props) => (
+ undefined}
+ filteringOptions={[{ name: 'test', option: 'test' }]}
+ isChecked={(option) => option === 'test'}
+ setFiltering={() => undefined}
+ />
+ }
+ />
+ ),
+ }),
+ },
+ {
+ accessorKey: 'city',
+ header: 'City',
+ size: 150,
+ },
+ {
+ accessorKey: 'state',
+ header: 'State',
+ size: 150,
+ },
+];
+
+export function Table() {
+ const {
+ fields: { sorting, pagination },
+ } = useTableQuery();
+
+ const { data, isLoading, isError, isRefetching } = useQuery({
+ queryKey: ['example', [sorting, pagination]],
+ queryFn: () => getTableData(),
+ });
+
+ const table = useMaterialReactTable({
+ columns,
+ data: !data ? [] : data,
+ state: {
+ isLoading,
+ showAlertBanner: isError,
+ showProgressBars: isRefetching,
+ },
+ enableColumnActions: false,
+ enableColumnFilters: false,
+ enableSorting: false,
+ renderTopToolbar: () => (
+
+ ),
+ });
+
+ return ;
+}
diff --git a/packages/apps/human-app/frontend/src/pages/protected.page.tsx b/packages/apps/human-app/frontend/src/pages/protected.page.tsx
new file mode 100644
index 0000000000..9156a566cf
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/protected.page.tsx
@@ -0,0 +1,9 @@
+import Box from '@mui/material/Box';
+
+export function ProtectedPage() {
+ return (
+
+ ProtectedPage
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/email-verification/email-verification.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/email-verification/email-verification.page.tsx
new file mode 100644
index 0000000000..6cff845073
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/email-verification/email-verification.page.tsx
@@ -0,0 +1,84 @@
+import Grid from '@mui/material/Grid';
+import { t } from 'i18next';
+import Typography from '@mui/material/Typography';
+import { z } from 'zod';
+import { Link } from 'react-router-dom';
+import { Button } from '@/components/ui/button';
+import { routerPaths } from '@/router/router-paths';
+import { useVerifyEmailQuery } from '@/api/servieces/worker/email-verification';
+import { SuccessLabel } from '@/components/ui/success-label';
+import {
+ PageCard,
+ PageCardError,
+ PageCardLoader,
+} from '@/components/ui/page-card';
+import { useLocationState } from '@/hooks/use-location-state';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+
+const tokenSchema = z.string().transform((value, ctx) => {
+ const token = value.split('=')[1];
+ if (!token) {
+ ctx.addIssue({
+ fatal: true,
+ code: z.ZodIssueCode.custom,
+ message: 'error',
+ });
+ }
+
+ return token;
+});
+
+export function EmailVerificationWorkerPage() {
+ const { field: token } = useLocationState({
+ schema: tokenSchema,
+ locationStorage: 'search',
+ });
+
+ if (token === undefined) {
+ return ;
+ }
+
+ return ;
+}
+
+export function EmailVerificationWorker({ token }: { token: string }) {
+ const {
+ error: emailVerificationWorkerError,
+ isError: isEmailVerificationWorkerError,
+ isPending: isEmailVerificationWorkerPending,
+ } = useVerifyEmailQuery({ token });
+
+ if (isEmailVerificationWorkerError) {
+ return (
+
+ );
+ }
+
+ if (isEmailVerificationWorkerPending) {
+ return ;
+ }
+
+ return (
+ {t('worker.emailVerification.title')}}
+ >
+
+
+ {t('worker.emailVerification.description')}
+
+
+ {t('worker.emailVerification.btn')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/email-verification/verify-email.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/email-verification/verify-email.page.tsx
new file mode 100644
index 0000000000..a16071813f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/email-verification/verify-email.page.tsx
@@ -0,0 +1,140 @@
+/* eslint-disable camelcase -- ...*/
+import { Grid, Typography } from '@mui/material';
+import { Trans, useTranslation } from 'react-i18next';
+import { Link, useNavigate } from 'react-router-dom';
+import { z } from 'zod';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { FormProvider, useForm } from 'react-hook-form';
+import { colorPalette } from '@/styles/color-palette';
+import { PageCard, PageCardLoader } from '@/components/ui/page-card';
+import { useLocationState } from '@/hooks/use-location-state';
+import { env } from '@/shared/env';
+import type { ResendEmailVerificationDto } from '@/api/servieces/worker/resend-email-verification';
+import {
+ resendEmailVerificationHcaptchaSchema,
+ useResendEmailVerificationWorkerMutation,
+ useResendEmailVerificationWorkerMutationState,
+} from '@/api/servieces/worker/resend-email-verification';
+import { Alert } from '@/components/ui/alert';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { FormCaptcha } from '@/components/h-captcha';
+import { Button } from '@/components/ui/button';
+import { useAuth } from '@/auth/use-auth';
+import { routerPaths } from '@/router/router-paths';
+
+export function VerifyEmailWorkerPage() {
+ const navigate = useNavigate();
+ const { signOut, user } = useAuth();
+ const isAuthenticated = Boolean(user);
+ const { t } = useTranslation();
+ const { field: routerState } = useLocationState({
+ keyInStorage: 'routerState',
+ schema: z.object({
+ email: z.string().email(),
+ resendOnMount: z.boolean().optional(),
+ }),
+ });
+ const mutationState = useResendEmailVerificationWorkerMutationState();
+ const { mutate: resendEmailVerificationMutation } =
+ useResendEmailVerificationWorkerMutation();
+
+ const methods = useForm>({
+ defaultValues: {
+ h_captcha_token: '',
+ },
+ resolver: zodResolver(resendEmailVerificationHcaptchaSchema),
+ });
+
+ const handleResend = (
+ data: Pick
+ ) => {
+ resendEmailVerificationMutation({
+ email: routerState?.email || '',
+ h_captcha_token: data.h_captcha_token,
+ });
+ };
+
+ if (mutationState?.status === 'pending') {
+ return ;
+ }
+
+ return (
+
+ {defaultErrorMessage(mutationState.error)}
+
+ ) : undefined
+ }
+ cancelRouterPathOrCallback={() => {
+ signOut();
+ navigate(routerPaths.homePage);
+ }}
+ title={t('worker.verifyEmail.title')}
+ >
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/enable-labeler.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/enable-labeler.page.tsx
new file mode 100644
index 0000000000..66be901547
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/enable-labeler.page.tsx
@@ -0,0 +1,104 @@
+import Grid from '@mui/material/Grid';
+import Paper from '@mui/material/Paper';
+import { t } from 'i18next';
+import Typography from '@mui/material/Typography';
+import { Navigate } from 'react-router-dom';
+import { useEffect } from 'react';
+import { colorPalette } from '@/styles/color-palette';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { useEnableHCaptchaLabelingMutation } from '@/api/servieces/worker/enable-hcaptcha-labeling';
+import { Button } from '@/components/ui/button';
+import { PageCardError } from '@/components/ui/page-card';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { breakpoints } from '@/styles/theme';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { routerPaths } from '@/router/router-paths';
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+
+export function EnableLabeler() {
+ const isMobile = useIsMobile();
+ const { closeNotification } = useProtectedLayoutNotification();
+ const { user } = useAuthenticatedUser();
+ const { mutate, error, isError, isPending, status } =
+ useEnableHCaptchaLabelingMutation();
+
+ useEffect(() => {
+ if (status === 'success') {
+ closeNotification();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- ...
+ }, [status]);
+
+ if (!user.wallet_address) {
+ return ;
+ }
+
+ if (user.site_key) {
+ return ;
+ }
+
+ if (isError) {
+ return ;
+ }
+
+ return (
+
+
+
+
+
+ {t('worker.enableHCaptchaLabeling.description')}
+
+
+ {
+ mutate();
+ }}
+ variant="contained"
+ >
+ {t('worker.enableHCaptchaLabeling.enableButton')}
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/hcaptcha-labeling.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/hcaptcha-labeling.page.tsx
new file mode 100644
index 0000000000..0eddbb0bb6
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/hcaptcha-labeling.page.tsx
@@ -0,0 +1,161 @@
+import HCaptcha from '@hcaptcha/react-hcaptcha';
+import Grid from '@mui/material/Grid';
+import { Paper, Typography } from '@mui/material';
+import { t } from 'i18next';
+import { useNavigate } from 'react-router-dom';
+import { useRef } from 'react';
+import { colorPalette } from '@/styles/color-palette';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { env } from '@/shared/env';
+import { breakpoints } from '@/styles/theme';
+import { Counter } from '@/components/ui/counter';
+import { useHCaptchaUserStats } from '@/api/servieces/worker/hcaptcha-user-stats';
+import { PageCardError, PageCardLoader } from '@/components/ui/page-card';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { useDailyHmtSpent } from '@/api/servieces/worker/daily-hmt-spent';
+import { getTomorrowDate } from '@/shared/helpers/counter-helpers';
+import { useSolveHCaptchaMutation } from '@/api/servieces/worker/solve-hcaptcha';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { useHCaptchaLabelingNotifications } from '@/hooks/use-hcaptcha-labeling-notifications';
+
+export function HcaptchaLabelingPage() {
+ const captchaRef = useRef(null);
+ const { user } = useAuthenticatedUser();
+ const { onSuccess, onError } = useHCaptchaLabelingNotifications();
+
+ const resetCaptcha = () => {
+ if (captchaRef.current) {
+ captchaRef.current.resetCaptcha();
+ }
+ };
+
+ const { mutate: solveHCaptchaMutation } = useSolveHCaptchaMutation({
+ onSuccess: async () => {
+ await onSuccess();
+ resetCaptcha();
+ },
+ onError: async (e) => {
+ await onError(e);
+ resetCaptcha();
+ },
+ });
+
+ const {
+ data: hcaptchaUserStats,
+ isPending: isHcaptchaUserStatsPending,
+ isError: isHcaptchaUserStatsError,
+ error: hcaptchaUserStatsError,
+ } = useHCaptchaUserStats();
+
+ const {
+ data: dailyHmtSpent,
+ isPending: isDailyHmtSpentPending,
+ isError: isDailyHmtSpentError,
+ error: dailyHmtSpentError,
+ } = useDailyHmtSpent();
+
+ const isMobile = useIsMobile();
+ const navigate = useNavigate();
+
+ const canSolveCaptcha =
+ dailyHmtSpent &&
+ hcaptchaUserStats &&
+ (hcaptchaUserStats.solved < env.VITE_DAILY_SOLVED_CAPTCHA_LIMIT ||
+ dailyHmtSpent.spend < env.VITE_HMT_DAILY_SPENT_LIMIT);
+
+ const hcaptchaOnSuccess = (token: string) => {
+ solveHCaptchaMutation({ token });
+ };
+
+ if (isHcaptchaUserStatsPending || isDailyHmtSpentPending) {
+ return ;
+ }
+
+ if (isHcaptchaUserStatsError || isDailyHmtSpentError) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ {t('worker.hcaptchaLabeling.description')}
+
+ {canSolveCaptcha ? (
+
+
+
+ ) : (
+
+
+ {t('worker.hcaptchaLabeling.noJobs')}
+
+
+ {
+ navigate(0);
+ }}
+ />
+
+
+ )}
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-accordion.tsx b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-accordion.tsx
new file mode 100644
index 0000000000..067424d31d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-accordion.tsx
@@ -0,0 +1,60 @@
+import Accordion from '@mui/material/Accordion';
+import AccordionSummary from '@mui/material/AccordionSummary';
+import AccordionDetails from '@mui/material/AccordionDetails';
+import Typography from '@mui/material/Typography';
+import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
+import Grid from '@mui/material/Grid';
+import { useEffect } from 'react';
+import { UserStatsDetails } from '@/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-details';
+import { useHCaptchaUserStats } from '@/api/servieces/worker/hcaptcha-user-stats';
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+
+const accordionWidth = { width: '284px' };
+
+export function UserStatsAccordion() {
+ const {
+ data: hcaptchaUserStats,
+ isPending: isHcaptchaUserStatsPending,
+ isError: isHcaptchaUserStatsError,
+ error: hcaptchaUserStatsError,
+ refetch: refetchUserStats,
+ } = useHCaptchaUserStats();
+ const { setTopNotification } = useProtectedLayoutNotification();
+
+ useEffect(() => {
+ if (isHcaptchaUserStatsError) {
+ setTopNotification({
+ type: 'warning',
+ content: defaultErrorMessage(hcaptchaUserStatsError),
+ });
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- ...
+ }, [isHcaptchaUserStatsError, hcaptchaUserStatsError]);
+
+ return (
+
+
+ }
+ id="panel1-header"
+ sx={{ ...accordionWidth, height: '76px' }}
+ >
+ hCapcha Statistics
+
+ {hcaptchaUserStats ? (
+
+ {
+ void refetchUserStats();
+ }}
+ stats={hcaptchaUserStats}
+ />
+
+ ) : null}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-details.tsx b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-details.tsx
new file mode 100644
index 0000000000..1a03ee59fc
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-details.tsx
@@ -0,0 +1,123 @@
+import { Divider, Grid, Typography } from '@mui/material';
+import { t } from 'i18next';
+import { colorPalette } from '@/styles/color-palette';
+import { RefreshIcon } from '@/components/ui/icons';
+import type { HCaptchaUserStatsSuccess } from '@/api/servieces/worker/hcaptcha-user-stats';
+
+export function UserStatsDetails({
+ stats,
+ refetch,
+}: {
+ stats: HCaptchaUserStatsSuccess;
+ refetch: () => void;
+}) {
+ return (
+
+
+
+
+
+ {t('worker.hcaptchaLabelingStats.allTime')}
+
+
+
+
+ {t('worker.hcaptchaLabelingStats.jobsServed')}
+
+
+ {stats.served}
+
+
+
+
+ {t('worker.hcaptchaLabelingStats.jobsComplete')}
+
+
+ {stats.solved}
+
+
+
+
+ {t('worker.hcaptchaLabelingStats.hmtEarned')}
+
+
+ {stats.balance.total}
+
+ {t('inputMasks.humanCurrencySuffix')}
+
+
+
+
+
+
+
+
+ {t('worker.hcaptchaLabelingStats.lastHour')}
+
+
+
+
+ {t('worker.hcaptchaLabelingStats.earnedLastHour')}
+
+
+ {stats.balance.recent}
+
+ {t('inputMasks.humanCurrencySuffix')}
+
+
+
+
+
+
+
+
+ {t('worker.hcaptchaLabelingStats.statisticsNotLive')}
+
+
+ {
+ refetch();
+ }}
+ sx={{
+ display: 'flex',
+ justifyContent: 'center',
+ alignItems: 'center',
+ ':hover': {
+ cursor: 'pointer',
+ },
+ }}
+ >
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-drawer.tsx b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-drawer.tsx
new file mode 100644
index 0000000000..3e4b5dc220
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-drawer.tsx
@@ -0,0 +1,91 @@
+import Box from '@mui/material/Box';
+import Drawer from '@mui/material/Drawer';
+import CssBaseline from '@mui/material/CssBaseline';
+import { Grid, Typography } from '@mui/material';
+import { t } from 'i18next';
+import { UserStatsDetails } from '@/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-details';
+import type { HCaptchaUserStatsSuccess } from '@/api/servieces/worker/hcaptcha-user-stats';
+import { useHCaptchaUserStats } from '@/api/servieces/worker/hcaptcha-user-stats';
+import { Loader } from '@/components/ui/loader';
+import { Alert } from '@/components/ui/alert';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+
+export interface UserStatsDrawerNavigationProps {
+ isOpen: boolean;
+}
+
+function UserStatsDrawerContent({
+ stats,
+ refetch,
+}: {
+ stats: HCaptchaUserStatsSuccess;
+ refetch: () => void;
+}) {
+ return (
+ <>
+
+ {t('worker.hcaptchaLabelingStats.hCapchaStatistics')}
+
+
+ >
+ );
+}
+
+export function UserStatsDrawer({ isOpen }: UserStatsDrawerNavigationProps) {
+ const {
+ data: hcaptchaUserStats,
+ error: hcaptchaUserStatsError,
+ status: hcaptchaUserStatsStatus,
+ refetch: hcaptchaUserStatsRefetch,
+ } = useHCaptchaUserStats();
+
+ return (
+
+
+
+
+ {hcaptchaUserStatsStatus === 'success' ? (
+ {
+ void hcaptchaUserStatsRefetch();
+ }}
+ stats={hcaptchaUserStats}
+ />
+ ) : null}
+ {hcaptchaUserStatsStatus === 'error' ? (
+
+ {defaultErrorMessage(hcaptchaUserStatsError)}
+
+ ) : null}
+ {hcaptchaUserStatsStatus === 'pending' ? (
+
+ ) : null}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/jobs-discovery.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/jobs-discovery.page.tsx
new file mode 100644
index 0000000000..615e4a2857
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/jobs-discovery.page.tsx
@@ -0,0 +1,39 @@
+import Paper from '@mui/material/Paper';
+import Grid from '@mui/material/Grid';
+import type { UseQueryResult } from '@tanstack/react-query';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { OraclesTable } from '@/pages/worker/jobs-discovery/oracles-table/oracles-table';
+import { OraclesTableJobTypesSelect } from '@/pages/worker/jobs-discovery/oracles-table/oracles-table-job-types-select';
+import { JOB_TYPES } from '@/shared/consts';
+import { colorPalette } from '@/styles/color-palette';
+import type { OraclesSuccessResponse } from '@/api/servieces/worker/oracles';
+import { useGetOracles } from '@/api/servieces/worker/oracles';
+
+export type OraclesDataQueryResult = UseQueryResult;
+
+export function JobsDiscoveryPage() {
+ const oraclesQueryResult = useGetOracles();
+ const isMobile = useIsMobile();
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table-job-types-select.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table-job-types-select.tsx
new file mode 100644
index 0000000000..a9c344dc6e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table-job-types-select.tsx
@@ -0,0 +1,36 @@
+import { FormProvider, useForm } from 'react-hook-form';
+import { useEffect } from 'react';
+import { Grid } from '@mui/material';
+import { useJobsTypesOraclesFilter } from '@/hooks/use-job-types-oracles-table';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { MultiSelect } from '@/components/data-entry/multi-select';
+
+export function OraclesTableJobTypesSelect({
+ jobTypes,
+}: {
+ jobTypes: string[];
+}) {
+ const isMobile = useIsMobile();
+ const { selectJobType } = useJobsTypesOraclesFilter();
+ const methods = useForm<{ jobType: string[] }>({
+ defaultValues: {
+ jobType: [],
+ },
+ });
+
+ const selectedJobType = methods.watch('jobType');
+
+ useEffect(() => {
+ selectJobType(selectedJobType);
+ }, [selectJobType, selectedJobType]);
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table-mobile.tsx
new file mode 100644
index 0000000000..0f37545fc1
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table-mobile.tsx
@@ -0,0 +1,84 @@
+import { Grid, Paper, Stack, Typography } from '@mui/material';
+import { t } from 'i18next';
+import { colorPalette } from '@/styles/color-palette';
+import { Chips } from '@/components/ui/chips';
+import { TableButton } from '@/components/ui/table-button';
+import { Loader } from '@/components/ui/loader';
+import { Alert } from '@/components/ui/alert';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import type { OraclesDataQueryResult } from '@/pages/worker/jobs-discovery/jobs-discovery.page';
+import { EvmAddress } from '@/pages/worker/jobs/components/evm-address';
+import { ListItem } from '@/components/ui/list-item';
+
+export function OraclesTableMobile({
+ selectOracle,
+ oraclesQueryDataResult: {
+ data: oraclesData,
+ isError: isOraclesDataError,
+ error: oraclesDataError,
+ isPending: isOraclesDataPending,
+ },
+}: {
+ selectOracle: (oracleAddress: string, jobTypes: string[]) => void;
+ oraclesQueryDataResult: OraclesDataQueryResult;
+}) {
+ if (isOraclesDataPending) {
+ return (
+
+
+
+ );
+ }
+
+ if (isOraclesDataError) {
+ return (
+
+ {defaultErrorMessage(oraclesDataError)}
+
+ );
+ }
+
+ return (
+
+ {oraclesData.map((d) => (
+
+
+
+
+
+
+ {d.url || ''}
+
+
+
+
+
+ {
+ selectOracle(d.address, d.jobTypes);
+ }}
+ >
+ {t('worker.oraclesTable.seeJobs')}
+
+
+ ))}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table.tsx
new file mode 100644
index 0000000000..8d78c4bfae
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs-discovery/oracles-table/oracles-table.tsx
@@ -0,0 +1,110 @@
+import { t } from 'i18next';
+import type { MRT_ColumnDef } from 'material-react-table';
+import {
+ MaterialReactTable,
+ useMaterialReactTable,
+} from 'material-react-table';
+import Grid from '@mui/material/Grid';
+import { useNavigate } from 'react-router-dom';
+import { type OracleSuccessResponse } from '@/api/servieces/worker/oracles';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { EvmAddress } from '@/pages/worker/jobs/components/evm-address';
+import { Chips } from '@/components/ui/chips';
+import { TableButton } from '@/components/ui/table-button';
+import { routerPaths } from '@/router/router-paths';
+import { OraclesTableMobile } from '@/pages/worker/jobs-discovery/oracles-table/oracles-table-mobile';
+import type { OraclesDataQueryResult } from '@/pages/worker/jobs-discovery/jobs-discovery.page';
+
+const getColumns = (
+ selectOracle: (oracleAddress: string) => void
+): MRT_ColumnDef[] => {
+ return [
+ {
+ accessorKey: 'url',
+ header: t('worker.oraclesTable.annotationTool'),
+ size: 100,
+ enableSorting: false,
+ },
+ {
+ accessorKey: 'address',
+ header: t('worker.oraclesTable.oracleAddress'),
+ size: 100,
+ enableSorting: true,
+ Cell: (props) => ,
+ },
+ {
+ accessorKey: 'jobTypes',
+ header: t('worker.oraclesTable.jobTypes'),
+ size: 100,
+ enableSorting: false,
+ Cell: (props) => {
+ return ;
+ },
+ },
+ {
+ accessorKey: 'url',
+ header: '',
+ size: 100,
+ enableSorting: false,
+ Cell: (props) => {
+ return (
+
+ {
+ selectOracle(props.row.original.address);
+ }}
+ >
+ {t('worker.oraclesTable.seeJobs')}
+
+
+ );
+ },
+ },
+ ];
+};
+
+export function OraclesTable({
+ oraclesQueryDataResult,
+}: {
+ oraclesQueryDataResult: OraclesDataQueryResult;
+}) {
+ const {
+ data: oraclesData,
+ isError: isOraclesDataError,
+ isRefetching: isOraclesDataRefetching,
+ isPending: isOraclesDataPending,
+ } = oraclesQueryDataResult;
+ const navigate = useNavigate();
+ const isMobile = useIsMobile();
+ const selectOracle = (oracleAddress: string) => {
+ navigate(`${routerPaths.worker.jobs}/${oracleAddress}`);
+ };
+
+ const table = useMaterialReactTable({
+ state: {
+ isLoading: isOraclesDataPending,
+ showAlertBanner: isOraclesDataError,
+ showProgressBars: isOraclesDataRefetching,
+ },
+ columns: getColumns(selectOracle),
+ data: oraclesData || [],
+ enableColumnActions: false,
+ enableColumnFilters: false,
+ enableSorting: false,
+ enablePagination: false,
+ enableTopToolbar: false,
+ });
+
+ return (
+ <>
+ {isMobile ? (
+
+ ) : (
+
+ )}
+ >
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-job-type-filter.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-job-type-filter.tsx
new file mode 100644
index 0000000000..ede50a271f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-job-type-filter.tsx
@@ -0,0 +1,37 @@
+/* eslint-disable camelcase --- ... */
+import capitalize from 'lodash/capitalize';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import { stringToUpperSnakeCase } from '@/shared/helpers/string-to-upper-snake-case';
+
+export function AvailableJobsJobTypeFilter({
+ jobTypes,
+}: {
+ jobTypes: string[];
+}) {
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ job_type: undefined,
+ });
+ }}
+ filteringOptions={jobTypes.map((jobType) => ({
+ name: capitalize(jobType),
+ option: jobType,
+ }))}
+ isChecked={(option) =>
+ stringToUpperSnakeCase(option) === filterParams.job_type
+ }
+ setFiltering={(jobType) => {
+ setFilterParams({
+ ...filterParams,
+ job_type: stringToUpperSnakeCase(jobType),
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-network-filter.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-network-filter.tsx
new file mode 100644
index 0000000000..00a6e1851a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-network-filter.tsx
@@ -0,0 +1,32 @@
+/* eslint-disable camelcase --- ... */
+import { chains } from '@/smart-contracts/chains';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+
+const allNetworks = chains.map(({ chainId, name }) => ({
+ option: chainId,
+ name,
+}));
+
+export function AvailableJobsNetworkFilter() {
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ chain_id: undefined,
+ });
+ }}
+ filteringOptions={allNetworks}
+ isChecked={(option) => option === filterParams.chain_id}
+ setFiltering={(chainId) => {
+ setFilterParams({
+ ...filterParams,
+ chain_id: chainId,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-reward-amount-sort.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-reward-amount-sort.tsx
new file mode 100644
index 0000000000..62535540c1
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-reward-amount-sort.tsx
@@ -0,0 +1,46 @@
+/* eslint-disable camelcase --- ... */
+import { t } from 'i18next';
+import { Sorting } from '@/components/ui/table/table-header-menu.tsx/sorting';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+
+export function AvailableJobsRewardAmountSort() {
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ const sortAscRewardAmount = () => {
+ setFilterParams({
+ ...filterParams,
+ sort_field: 'reward_amount',
+ sort: 'ASC',
+ });
+ };
+
+ const sortDescRewardAmount = () => {
+ setFilterParams({
+ ...filterParams,
+ sort_field: 'reward_amount',
+ sort: 'DESC',
+ });
+ };
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ sort_field: undefined,
+ sort: undefined,
+ });
+ }}
+ sortingOptions={[
+ {
+ label: t('worker.jobs.sortDirection.fromHighest'),
+ sortCallback: sortDescRewardAmount,
+ },
+ {
+ label: t('worker.jobs.sortDirection.fromLowest'),
+ sortCallback: sortAscRewardAmount,
+ },
+ ]}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-status-filter.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-status-filter.tsx
new file mode 100644
index 0000000000..3f215b22b1
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-status-filter.tsx
@@ -0,0 +1,30 @@
+import capitalize from 'lodash/capitalize';
+import { jobStatuses } from '@/hooks/use-my-jobs-filter-store';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+
+export function AvailableJobsStatusFilter() {
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ status: undefined,
+ });
+ }}
+ filteringOptions={jobStatuses.map((status) => ({
+ name: capitalize(status),
+ option: status,
+ }))}
+ isChecked={(status) => status === filterParams.status}
+ setFiltering={(status) => {
+ setFilterParams({
+ ...filterParams,
+ status,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-table.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-table.tsx
new file mode 100644
index 0000000000..281e87499a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/desktop/available-jobs-table.tsx
@@ -0,0 +1,225 @@
+/* eslint-disable camelcase -- ... */
+import type { MRT_ColumnDef } from 'material-react-table';
+import {
+ MaterialReactTable,
+ useMaterialReactTable,
+} from 'material-react-table';
+import { t } from 'i18next';
+import { useEffect, useMemo, useState } from 'react';
+import { Grid, Typography } from '@mui/material';
+import { SearchForm } from '@/pages/playground/table-example/table-search-form';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import {
+ useGetAvailableJobsData,
+ type AvailableJob,
+} from '@/api/servieces/worker/available-jobs-data';
+import type { AssignJobBody } from '@/api/servieces/worker/assign-job';
+import { useAssignJobMutation } from '@/api/servieces/worker/assign-job';
+import { EvmAddress } from '@/pages/worker/jobs/components/evm-address';
+import { RewardAmount } from '@/pages/worker/jobs/components/reward-amount';
+import { getNetworkName } from '@/smart-contracts/get-network-name';
+import { Chip } from '@/components/ui/chip';
+import { useJobsNotifications } from '@/hooks/use-jobs-notifications';
+import { colorPalette } from '@/styles/color-palette';
+import { TableButton } from '@/components/ui/table-button';
+import { TableHeaderCell } from '@/components/ui/table/table-header-cell';
+import { JOB_TYPES } from '@/shared/consts';
+import { AvailableJobsNetworkFilter } from '@/pages/worker/jobs/components/available-jobs/desktop/available-jobs-network-filter';
+import { AvailableJobsRewardAmountSort } from '@/pages/worker/jobs/components/available-jobs/desktop/available-jobs-reward-amount-sort';
+import { AvailableJobsJobTypeFilter } from '@/pages/worker/jobs/components/available-jobs/desktop/available-jobs-job-type-filter';
+
+export type AvailableJobsTableData = AvailableJob & {
+ rewardTokenInfo: {
+ reward_amount?: number;
+ reward_token?: string;
+ };
+};
+
+const getColumns = (callbacks: {
+ assignJob: (data: AssignJobBody) => undefined;
+}): MRT_ColumnDef[] => {
+ return [
+ {
+ accessorKey: 'job_description',
+ header: t('worker.jobs.jobDescription'),
+ size: 100,
+ enableSorting: false,
+ },
+ {
+ accessorKey: 'escrow_address',
+ header: t('worker.jobs.escrowAddress'),
+ size: 100,
+ enableSorting: false,
+ Cell: (props) => {
+ return ;
+ },
+ },
+ {
+ accessorKey: 'chain_id',
+ header: t('worker.jobs.network'),
+ size: 100,
+ enableSorting: false,
+ Cell: () => {
+ return getNetworkName();
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => {
+ return (
+ }
+ />
+ );
+ },
+ }),
+ },
+ {
+ accessorKey: 'reward_amount',
+ header: t('worker.jobs.rewardAmount'),
+ size: 100,
+ enableSorting: false,
+ Cell: (props) => {
+ const { reward_amount, reward_token } = props.row.original;
+ return (
+
+ );
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => (
+ }
+ />
+ ),
+ }),
+ },
+ {
+ accessorKey: 'job_type',
+ header: t('worker.jobs.jobType'),
+ size: 200,
+ enableSorting: false,
+ Cell: (props) => {
+ return ;
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => {
+ return (
+
+ }
+ />
+ );
+ },
+ }),
+ },
+ {
+ accessorKey: 'escrow_address',
+ header: '',
+ size: 100,
+ enableSorting: false,
+ Cell: (props) => {
+ const { escrow_address, chain_id } = props.row.original;
+ return (
+
+ {
+ callbacks.assignJob({ escrow_address, chain_id });
+ }}
+ >
+
+ {t('worker.jobs.selectJob')}
+
+
+
+ );
+ },
+ },
+ ];
+};
+
+export function AvailableJobsTable() {
+ const { setSearchEscrowAddress, setPageParams, filterParams } =
+ useJobsFilterStore();
+ const { onJobAssignmentError, onJobAssignmentSuccess } =
+ useJobsNotifications();
+ const { data: tableData, status: tableStatus } = useGetAvailableJobsData();
+ const memoizedTableDataResults = useMemo(
+ () => tableData?.results || [],
+ [tableData?.results]
+ );
+
+ const { mutate: assignJobMutation, isPending: isAssignJobMutationPending } =
+ useAssignJobMutation({
+ onSuccess: onJobAssignmentSuccess,
+ onError: onJobAssignmentError,
+ });
+
+ const [paginationState, setPaginationState] = useState({
+ pageIndex: 0,
+ pageSize: 5,
+ });
+
+ useEffect(() => {
+ if (!(paginationState.pageSize === 5 || paginationState.pageSize === 10))
+ return;
+ setPageParams(paginationState.pageIndex, paginationState.pageSize);
+ }, [paginationState, setPageParams]);
+
+ useEffect(() => {
+ setPaginationState({
+ pageIndex: filterParams.page,
+ pageSize: filterParams.page_size,
+ });
+ }, [filterParams.page, filterParams.page_size]);
+
+ const table = useMaterialReactTable({
+ columns: getColumns({
+ assignJob: (data) => {
+ assignJobMutation(data);
+ },
+ }),
+ data: memoizedTableDataResults,
+ state: {
+ isLoading: tableStatus === 'pending',
+ showAlertBanner: tableStatus === 'error',
+ showProgressBars: tableStatus === 'pending' || isAssignJobMutationPending,
+ pagination: paginationState,
+ },
+ enablePagination: Boolean(tableData?.total_pages),
+ manualPagination: true,
+ onPaginationChange: setPaginationState,
+ muiPaginationProps: {
+ rowsPerPageOptions: [5, 10],
+ },
+ pageCount: tableData?.total_pages || -1,
+ rowCount: tableData?.total_results,
+ enableColumnActions: false,
+ enableColumnFilters: false,
+ enableSorting: true,
+ manualSorting: true,
+ renderTopToolbar: () => (
+ {
+ setSearchEscrowAddress(address);
+ }}
+ />
+ ),
+ });
+
+ return ;
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-drawer-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-drawer-mobile.tsx
new file mode 100644
index 0000000000..043f8cff0d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-drawer-mobile.tsx
@@ -0,0 +1,197 @@
+/* eslint-disable camelcase --- response from api */
+import Box from '@mui/material/Box';
+import Drawer from '@mui/material/Drawer';
+import CssBaseline from '@mui/material/CssBaseline';
+import { Divider, IconButton, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import CloseIcon from '@mui/icons-material/Close';
+import type { Dispatch, SetStateAction } from 'react';
+import { colorPalette } from '@/styles/color-palette';
+import { Button } from '@/components/ui/button';
+import { HumanLogoIcon, SortArrow } from '@/components/ui/icons';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import { AvailableJobsNetworkFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-network-filter-mobile';
+import { AvailableJobsStatusFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-status-filter-mobile';
+import { AvailableJobsJobTypeFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-job-type-filter-mobile';
+import { JOB_TYPES } from '@/shared/consts';
+
+interface DrawerMobileProps {
+ setIsMobileFilterDrawerOpen: Dispatch>;
+}
+export function AvailableJobsDrawerMobile({
+ setIsMobileFilterDrawerOpen,
+}: DrawerMobileProps) {
+ const { t } = useTranslation();
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ return (
+
+
+
+
+
+
+ {
+ setIsMobileFilterDrawerOpen(false);
+ }}
+ sx={{
+ zIndex: '99999999',
+ marginRight: '15px',
+ backgroundColor: colorPalette.white,
+ }}
+ >
+
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.sortBy')}
+
+
+ {t('worker.jobs.rewardAmount')}
+
+
+
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'DESC',
+ sort_field: 'reward_amount',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ {t('worker.jobs.sortDirection.fromHighest')}
+
+
+
+
+
+ {' '}
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'ASC',
+ sort_field: 'reward_amount',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ From lowest
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {t('worker.jobs.network')}
+
+
+
+
+
+
+
+ {t('worker.jobs.jobType')}
+
+
+
+
+
+
+ {t('worker.jobs.status')}
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-job-type-filter-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-job-type-filter-mobile.tsx
new file mode 100644
index 0000000000..fcfe7e8111
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-job-type-filter-mobile.tsx
@@ -0,0 +1,40 @@
+/* eslint-disable camelcase --- ... */
+import capitalize from 'lodash/capitalize';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import { stringToUpperSnakeCase } from '@/shared/helpers/string-to-upper-snake-case';
+
+export function AvailableJobsJobTypeFilterMobile({
+ jobTypes,
+}: {
+ jobTypes: string[];
+}) {
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ job_type: undefined,
+ page: 0,
+ });
+ }}
+ filteringOptions={jobTypes.map((jobType) => ({
+ name: capitalize(jobType),
+ option: jobType.toUpperCase(),
+ }))}
+ isChecked={(option) =>
+ stringToUpperSnakeCase(option) === filterParams.job_type
+ }
+ isMobile={false}
+ setFiltering={(jobType) => {
+ setFilterParams({
+ ...filterParams,
+ job_type: stringToUpperSnakeCase(jobType),
+ page: 0,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-network-filter-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-network-filter-mobile.tsx
new file mode 100644
index 0000000000..fca201b624
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-network-filter-mobile.tsx
@@ -0,0 +1,35 @@
+/* eslint-disable camelcase --- ... */
+import { chains } from '@/smart-contracts/chains';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+
+const allNetworks = chains.map(({ chainId, name }) => ({
+ option: chainId,
+ name,
+}));
+
+export function AvailableJobsNetworkFilterMobile() {
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ chain_id: undefined,
+ page: 0,
+ });
+ }}
+ filteringOptions={allNetworks}
+ isChecked={(option) => option === filterParams.chain_id}
+ isMobile={false}
+ setFiltering={(chainId) => {
+ setFilterParams({
+ ...filterParams,
+ chain_id: chainId,
+ page: 0,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-status-filter-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-status-filter-mobile.tsx
new file mode 100644
index 0000000000..efcb13c5d7
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-status-filter-mobile.tsx
@@ -0,0 +1,33 @@
+import capitalize from 'lodash/capitalize';
+import { jobStatuses } from '@/hooks/use-my-jobs-filter-store';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+
+export function AvailableJobsStatusFilterMobile() {
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ status: undefined,
+ page: 0,
+ });
+ }}
+ filteringOptions={jobStatuses.map((status) => ({
+ name: capitalize(status),
+ option: status,
+ }))}
+ isChecked={(status) => status === filterParams.status}
+ isMobile={false}
+ setFiltering={(status) => {
+ setFilterParams({
+ ...filterParams,
+ status,
+ page: 0,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-table-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-table-mobile.tsx
new file mode 100644
index 0000000000..5b38bbaf52
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/available-jobs/mobile/available-jobs-table-mobile.tsx
@@ -0,0 +1,186 @@
+/* eslint-disable camelcase -- ... */
+import { Grid, List, Paper, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { useEffect, useState, type Dispatch, type SetStateAction } from 'react';
+import { colorPalette } from '@/styles/color-palette';
+import { Button } from '@/components/ui/button';
+import { SearchForm } from '@/pages/playground/table-example/table-search-form';
+import { FiltersButtonIcon } from '@/components/ui/icons';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import { Alert } from '@/components/ui/alert';
+import { getNetworkName } from '@/smart-contracts/get-network-name';
+import { useAssignJobMutation } from '@/api/servieces/worker/assign-job';
+import { useJobsNotifications } from '@/hooks/use-jobs-notifications';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import type { AvailableJob } from '@/api/servieces/worker/available-jobs-data';
+import { useInfiniteGetAvailableJobsData } from '@/api/servieces/worker/available-jobs-data';
+import { Loader } from '@/components/ui/loader';
+import { TableButton } from '@/components/ui/table-button';
+import { EvmAddress } from '@/pages/worker/jobs/components/evm-address';
+import { Chip } from '@/components/ui/chip';
+import { RewardAmount } from '@/pages/worker/jobs/components/reward-amount';
+import { ListItem } from '@/components/ui/list-item';
+
+interface AvailableJobsTableMobileProps {
+ setIsMobileFilterDrawerOpen: Dispatch>;
+}
+
+export function AvailableJobsTableMobile({
+ setIsMobileFilterDrawerOpen,
+}: AvailableJobsTableMobileProps) {
+ const [allPages, setAllPages] = useState([]);
+ const { onJobAssignmentError, onJobAssignmentSuccess } =
+ useJobsNotifications();
+
+ const { mutate: assignJobMutation } = useAssignJobMutation({
+ onSuccess: onJobAssignmentSuccess,
+ onError: onJobAssignmentError,
+ });
+
+ const {
+ data: tableData,
+ status: tableStatus,
+ isError: isTableError,
+ error: tableError,
+ fetchNextPage,
+ hasNextPage,
+ } = useInfiniteGetAvailableJobsData();
+ const { filterParams, setPageParams } = useJobsFilterStore();
+ const { t } = useTranslation();
+ const { setSearchEscrowAddress } = useJobsFilterStore();
+
+ useEffect(() => {
+ if (!tableData) return;
+ const pagesFromRes = tableData.pages.flatMap((pages) => pages.results);
+ if (filterParams.page === 0) {
+ setAllPages(pagesFromRes);
+ } else {
+ setAllPages((state) => [...state, ...pagesFromRes]);
+ }
+ }, [tableData, filterParams.page]);
+
+ return (
+ <>
+
+ {
+ setIsMobileFilterDrawerOpen(true);
+ }}
+ sx={{
+ marginBottom: '32px',
+ marginTop: '21px',
+ }}
+ variant="outlined"
+ >
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {isTableError ? (
+
+ {defaultErrorMessage(tableError)}
+
+ ) : null}
+ {tableStatus === 'pending' ? (
+
+
+
+ ) : null}
+ {allPages.map((d) => (
+
+
+
+
+
+
+ {d.job_description}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {getNetworkName()}
+
+
+
+
+
+
+
+ {
+ assignJobMutation({
+ escrow_address: d.escrow_address,
+ chain_id: d.chain_id,
+ });
+ }}
+ size="small"
+ sx={{
+ marginTop: '15px',
+ }}
+ type="button"
+ variant="contained"
+ >
+ {t('worker.jobs.selectJob')}
+
+
+
+
+
+ ))}
+ {hasNextPage ? (
+ {
+ setPageParams(filterParams.page + 1, filterParams.page_size);
+ void fetchNextPage();
+ }}
+ variant="outlined"
+ >
+ {t('worker.jobs.next')}
+
+ ) : null}
+
+ >
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/drawer-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/drawer-mobile.tsx
new file mode 100644
index 0000000000..f010b3c6d8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/drawer-mobile.tsx
@@ -0,0 +1,274 @@
+/* eslint-disable camelcase --- response from api */
+import Box from '@mui/material/Box';
+import Drawer from '@mui/material/Drawer';
+import CssBaseline from '@mui/material/CssBaseline';
+import {
+ Checkbox,
+ Divider,
+ IconButton,
+ Stack,
+ Typography,
+} from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import CloseIcon from '@mui/icons-material/Close';
+import type { Dispatch, SetStateAction } from 'react';
+import { colorPalette } from '@/styles/color-palette';
+import { Button } from '@/components/ui/button';
+import { HumanLogoIcon, SortArrow } from '@/components/ui/icons';
+import type { JobsFilterStoreProps } from '@/hooks/use-jobs-filter-store';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import { AvailableJobsNetworkFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-network-filter-mobile';
+import { AvailableJobsStatusFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-status-filter-mobile';
+import { AvailableJobsJobTypeFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-job-type-filter-mobile';
+import { JOB_TYPES } from '@/shared/consts';
+
+interface DrawerMobileProps {
+ selectedTab: string;
+ setIsMobileFilterDrawerOpen: Dispatch>;
+}
+export function DrawerMobile({
+ selectedTab,
+ setIsMobileFilterDrawerOpen,
+}: DrawerMobileProps) {
+ const { t } = useTranslation();
+ const { setFilterParams, filterParams } = useJobsFilterStore();
+
+ const handleCheckboxClick = (
+ paramName: keyof JobsFilterStoreProps['filterParams'],
+ paramValue: string
+ ) => {
+ if (filterParams[paramName] === paramValue) {
+ setFilterParams({
+ ...filterParams,
+ [paramName]: undefined,
+ });
+ } else {
+ setFilterParams({
+ ...filterParams,
+ [paramName]: paramValue,
+ });
+ }
+ };
+
+ return (
+
+
+
+
+
+
+ {
+ setIsMobileFilterDrawerOpen(false);
+ }}
+ sx={{
+ zIndex: '99999999',
+ marginRight: '15px',
+ backgroundColor: colorPalette.white,
+ }}
+ >
+
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.sortBy')}
+
+
+ {t('worker.jobs.rewardAmount')}
+
+
+ {' '}
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'DESC',
+ sort_field: 'reward_amount',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ {t('worker.jobs.sortDirection.fromHighest')}
+
+
+
+
+
+ {' '}
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'ASC',
+ sort_field: 'reward_amount',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ From lowest
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {t('worker.jobs.network')}
+
+
+
+
+
+
+
+ {t('worker.jobs.jobType')}
+
+
+
+
+
+
+ {t('worker.jobs.status')}
+
+ <>
+
+ {selectedTab === 'myJobs' && (
+ <>
+
+ {
+ handleCheckboxClick('status', 'VALIDATION');
+ }}
+ />
+
+ {t('worker.jobs.mobileFilterDrawer.jobsStatus.validation')}
+
+
+
+ {
+ handleCheckboxClick('status', 'EXPIRED');
+ }}
+ />
+
+ {t('worker.jobs.mobileFilterDrawer.jobsStatus.expired')}
+
+
+
+ {
+ handleCheckboxClick('status', 'REJECTED');
+ }}
+ />
+
+ {t('worker.jobs.mobileFilterDrawer.jobsStatus.rejected')}
+
+
+ >
+ )}
+ >
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/evm-address.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/evm-address.tsx
new file mode 100644
index 0000000000..6055a13fd2
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/evm-address.tsx
@@ -0,0 +1,22 @@
+import Tooltip from '@mui/material/Tooltip';
+import Typography from '@mui/material/Typography';
+import { shortenEscrowAddress } from '@/shared/helpers/shorten-escrow-address';
+import { breakpoints } from '@/styles/theme';
+import { colorPalette } from '@/styles/color-palette';
+
+export function EvmAddress({ address }: { address: string }) {
+ return (
+
+
+ {shortenEscrowAddress(address)}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/jobs-tab-panel.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/jobs-tab-panel.tsx
new file mode 100644
index 0000000000..c38c850832
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/jobs-tab-panel.tsx
@@ -0,0 +1,20 @@
+import { Box } from '@mui/material';
+
+interface TabPanelProps {
+ children?: React.ReactNode;
+ index: number;
+ activeTab: number;
+}
+
+export function TabPanel({ children, index, activeTab }: TabPanelProps) {
+ return (
+
+ {activeTab === index && {children} }
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-button.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-button.tsx
new file mode 100644
index 0000000000..de8ac73326
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-button.tsx
@@ -0,0 +1,19 @@
+import { useTranslation } from 'react-i18next';
+import { TableButton } from '@/components/ui/table-button';
+
+interface MyJobsButtonProps {
+ status: string;
+}
+
+export function MyJobsButton({ status }: MyJobsButtonProps) {
+ // TODO add correct implementation depending on job status
+ const { t } = useTranslation();
+ if (status === 'RESIGN') {
+ return {t('worker.jobs.resign')} ;
+ }
+ if (status === 'ACTIVE') {
+ return {t('worker.jobs.solve')} ;
+ }
+
+ return {t('worker.jobs.solve')} ;
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-expires-at-sort.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-expires-at-sort.tsx
new file mode 100644
index 0000000000..45a8d110ed
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-expires-at-sort.tsx
@@ -0,0 +1,46 @@
+/* eslint-disable camelcase --- ... */
+import { t } from 'i18next';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { Sorting } from '@/components/ui/table/table-header-menu.tsx/sorting';
+
+export function MyJobsExpiresAtSort() {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ const sortAscExpiresAt = () => {
+ setFilterParams({
+ ...filterParams,
+ sort_field: 'expires_at',
+ sort: 'ASC',
+ });
+ };
+
+ const sortDescExpiresAt = () => {
+ setFilterParams({
+ ...filterParams,
+ sort_field: 'expires_at',
+ sort: 'DESC',
+ });
+ };
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ sort_field: undefined,
+ sort: undefined,
+ });
+ }}
+ sortingOptions={[
+ {
+ label: t('worker.jobs.sortDirection.closestToNow'),
+ sortCallback: sortAscExpiresAt,
+ },
+ {
+ label: t('worker.jobs.sortDirection.furthestToNow'),
+ sortCallback: sortDescExpiresAt,
+ },
+ ]}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-job-type-filter.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-job-type-filter.tsx
new file mode 100644
index 0000000000..1464cf443b
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-job-type-filter.tsx
@@ -0,0 +1,33 @@
+/* eslint-disable camelcase --- ... */
+import capitalize from 'lodash/capitalize';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { stringToUpperSnakeCase } from '@/shared/helpers/string-to-upper-snake-case';
+
+export function MyJobsJobTypeFilter({ jobTypes }: { jobTypes: string[] }) {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ job_type: undefined,
+ });
+ }}
+ filteringOptions={jobTypes.map((jobType) => ({
+ name: capitalize(jobType),
+ option: jobType,
+ }))}
+ isChecked={(option) =>
+ stringToUpperSnakeCase(option) === filterParams.job_type
+ }
+ setFiltering={(jobType) => {
+ setFilterParams({
+ ...filterParams,
+ job_type: stringToUpperSnakeCase(jobType),
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-network-filter.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-network-filter.tsx
new file mode 100644
index 0000000000..b7942d49f8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-network-filter.tsx
@@ -0,0 +1,32 @@
+/* eslint-disable camelcase --- ... */
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { chains } from '@/smart-contracts/chains';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+
+const allNetworks = chains.map(({ chainId, name }) => ({
+ option: chainId,
+ name,
+}));
+
+export function MyJobsNetworkFilter() {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ chain_id: undefined,
+ });
+ }}
+ filteringOptions={allNetworks}
+ isChecked={(option) => option === filterParams.chain_id}
+ setFiltering={(chainId) => {
+ setFilterParams({
+ ...filterParams,
+ chain_id: chainId,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-reward-amount-sort.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-reward-amount-sort.tsx
new file mode 100644
index 0000000000..9ceb303393
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-reward-amount-sort.tsx
@@ -0,0 +1,46 @@
+/* eslint-disable camelcase --- ... */
+import { t } from 'i18next';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { Sorting } from '@/components/ui/table/table-header-menu.tsx/sorting';
+
+export function MyJobsRewardAmountSort() {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ const sortAscRewardAmount = () => {
+ setFilterParams({
+ ...filterParams,
+ sort_field: 'reward_amount',
+ sort: 'ASC',
+ });
+ };
+
+ const sortDescRewardAmount = () => {
+ setFilterParams({
+ ...filterParams,
+ sort_field: 'reward_amount',
+ sort: 'DESC',
+ });
+ };
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ sort_field: undefined,
+ sort: undefined,
+ });
+ }}
+ sortingOptions={[
+ {
+ label: t('worker.jobs.sortDirection.fromHighest'),
+ sortCallback: sortDescRewardAmount,
+ },
+ {
+ label: t('worker.jobs.sortDirection.fromLowest'),
+ sortCallback: sortAscRewardAmount,
+ },
+ ]}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-status-filter.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-status-filter.tsx
new file mode 100644
index 0000000000..30d501227e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-status-filter.tsx
@@ -0,0 +1,32 @@
+import capitalize from 'lodash/capitalize';
+import {
+ jobStatuses,
+ useMyJobsFilterStore,
+} from '@/hooks/use-my-jobs-filter-store';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+
+export function MyJobsStatusFilter() {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ status: undefined,
+ });
+ }}
+ filteringOptions={jobStatuses.map((status) => ({
+ name: capitalize(status),
+ option: status,
+ }))}
+ isChecked={(status) => status === filterParams.status}
+ setFiltering={(status) => {
+ setFilterParams({
+ ...filterParams,
+ status,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-table.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-table.tsx
new file mode 100644
index 0000000000..0afc343c6d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/desktop/my-jobs-table.tsx
@@ -0,0 +1,262 @@
+/* eslint-disable camelcase -- ...*/
+import { t } from 'i18next';
+import { useEffect, useMemo, useState } from 'react';
+import Grid from '@mui/material/Grid';
+import { Link, useParams } from 'react-router-dom';
+import {
+ MaterialReactTable,
+ useMaterialReactTable,
+ type MRT_ColumnDef,
+} from 'material-react-table';
+import { SearchForm } from '@/pages/playground/table-example/table-search-form';
+import { TableHeaderCell } from '@/components/ui/table/table-header-cell';
+import {
+ useGetMyJobsData,
+ type MyJob,
+} from '@/api/servieces/worker/my-jobs-data';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { getNetworkName } from '@/smart-contracts/get-network-name';
+import { RewardAmount } from '@/pages/worker/jobs/components/reward-amount';
+import { Chip } from '@/components/ui/chip';
+import { formatDate } from '@/shared/helpers/format-date';
+import { EvmAddress } from '@/pages/worker/jobs/components/evm-address';
+import { MyJobsJobTypeFilter } from '@/pages/worker/jobs/components/my-jobs/desktop/my-jobs-job-type-filter';
+import { MyJobsRewardAmountSort } from '@/pages/worker/jobs/components/my-jobs/desktop/my-jobs-reward-amount-sort';
+import { MyJobsStatusFilter } from '@/pages/worker/jobs/components/my-jobs/desktop/my-jobs-status-filter';
+import { MyJobsExpiresAtSort } from '@/pages/worker/jobs/components/my-jobs/desktop/my-jobs-expires-at-sort';
+import { MyJobsNetworkFilter } from '@/pages/worker/jobs/components/my-jobs/desktop/my-jobs-network-filter';
+import { TableButton } from '@/components/ui/table-button';
+import { useRejectTaskMutation } from '@/api/servieces/worker/reject-task';
+import { RejectButton } from '@/pages/worker/jobs/components/reject-button';
+import { JOB_TYPES } from '@/shared/consts';
+import { parseJobStatusChipColor } from '../parse-job-status-chip-color';
+
+const getColumnsDefinition = (
+ resignJob: (assignment_id: string) => void
+): MRT_ColumnDef[] => [
+ {
+ accessorKey: 'escrow_address',
+ header: t('worker.jobs.escrowAddress'),
+ size: 100,
+ enableSorting: true,
+ Cell: (props) => {
+ return ;
+ },
+ },
+ {
+ accessorKey: 'network',
+ header: t('worker.jobs.network'),
+ size: 100,
+ Cell: () => {
+ return getNetworkName();
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => {
+ return (
+ }
+ />
+ );
+ },
+ }),
+ },
+ {
+ accessorKey: 'reward_amount',
+ header: t('worker.jobs.rewardAmount'),
+ size: 100,
+ enableSorting: true,
+ Cell: (props) => {
+ const { reward_amount, reward_token } = props.row.original;
+ return (
+
+ );
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => (
+ }
+ />
+ ),
+ }),
+ },
+ {
+ accessorKey: 'job_type',
+ header: t('worker.jobs.jobType'),
+ size: 100,
+ enableSorting: true,
+ Cell: (props) => {
+ return ;
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => {
+ return (
+ }
+ />
+ );
+ },
+ }),
+ },
+ {
+ accessorKey: 'expires_at',
+ header: t('worker.jobs.expiresAt'),
+ size: 100,
+ enableSorting: true,
+ Cell: (props) => {
+ return formatDate(props.row.original.expires_at);
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => {
+ return (
+ }
+ />
+ );
+ },
+ }),
+ },
+ {
+ accessorKey: 'status',
+ header: t('worker.jobs.status'),
+ size: 100,
+ enableSorting: true,
+ Cell: (props) => {
+ const status = props.row.original.status;
+ return (
+
+ );
+ },
+ muiTableHeadCellProps: () => ({
+ component: (props) => {
+ return (
+ }
+ />
+ );
+ },
+ }),
+ },
+ {
+ accessorKey: 'assignment_id',
+ header: '',
+ size: 100,
+ enableSorting: true,
+ Cell: (props) => {
+ const { url, assignment_id, status } = props.row.original;
+ const buttonDisabled = status !== 'ACTIVE';
+ return (
+
+
+ {t('worker.jobs.solve')}
+
+ {
+ if (buttonDisabled) return;
+ resignJob(assignment_id);
+ }}
+ />
+
+ );
+ },
+ },
+];
+
+export function MyJobsTable() {
+ const { setSearchEscrowAddress, setPageParams, filterParams } =
+ useMyJobsFilterStore();
+ const { data: tableData, status: tableStatus } = useGetMyJobsData();
+ const memoizedTableDataResults = useMemo(
+ () => tableData?.results || [],
+ [tableData?.results]
+ );
+
+ const { mutate: rejectTaskMutation } = useRejectTaskMutation();
+ const { address: oracle_address } = useParams<{ address: string }>();
+
+ const [paginationState, setPaginationState] = useState({
+ pageIndex: 0,
+ pageSize: 5,
+ });
+
+ const rejectTask = (address: string) => {
+ return (assignment_id: string) => {
+ rejectTaskMutation({ oracle_address: address, assignment_id });
+ };
+ };
+ useEffect(() => {
+ if (!(paginationState.pageSize === 5 || paginationState.pageSize === 10))
+ return;
+ setPageParams(paginationState.pageIndex, paginationState.pageSize);
+ }, [paginationState, setPageParams]);
+
+ useEffect(() => {
+ setPaginationState({
+ pageIndex: filterParams.page,
+ pageSize: filterParams.page_size,
+ });
+ }, [filterParams.page, filterParams.page_size]);
+
+ const table = useMaterialReactTable({
+ columns: getColumnsDefinition(rejectTask(oracle_address || '')),
+ data: memoizedTableDataResults,
+ state: {
+ isLoading: tableStatus === 'pending',
+ showAlertBanner: tableStatus === 'error',
+ showProgressBars: tableStatus === 'pending',
+ pagination: paginationState,
+ },
+ enablePagination: Boolean(tableData?.total_pages),
+ manualPagination: true,
+ onPaginationChange: (updater) => {
+ setPaginationState(updater);
+ },
+ muiPaginationProps: {
+ rowsPerPageOptions: [5, 10],
+ },
+ pageCount: tableData?.total_pages || -1,
+ rowCount: tableData?.total_results,
+ enableColumnActions: false,
+ enableColumnFilters: false,
+ enableSorting: false,
+ renderTopToolbar: () => (
+ {
+ setSearchEscrowAddress(address);
+ }}
+ />
+ ),
+ });
+
+ return ;
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-drawer-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-drawer-mobile.tsx
new file mode 100644
index 0000000000..3a7b8318b8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-drawer-mobile.tsx
@@ -0,0 +1,257 @@
+/* eslint-disable camelcase --- response from api */
+import Box from '@mui/material/Box';
+import Drawer from '@mui/material/Drawer';
+import CssBaseline from '@mui/material/CssBaseline';
+import { Divider, IconButton, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import CloseIcon from '@mui/icons-material/Close';
+import type { Dispatch, SetStateAction } from 'react';
+import { colorPalette } from '@/styles/color-palette';
+import { Button } from '@/components/ui/button';
+import { HumanLogoIcon, SortArrow } from '@/components/ui/icons';
+import { AvailableJobsNetworkFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-network-filter-mobile';
+import { AvailableJobsStatusFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-status-filter-mobile';
+import { AvailableJobsJobTypeFilterMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-job-type-filter-mobile';
+import { JOB_TYPES } from '@/shared/consts';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+
+interface DrawerMobileProps {
+ setIsMobileFilterDrawerOpen: Dispatch>;
+}
+export function MyJobsDrawerMobile({
+ setIsMobileFilterDrawerOpen,
+}: DrawerMobileProps) {
+ const { t } = useTranslation();
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ return (
+
+
+
+
+
+
+ {
+ setIsMobileFilterDrawerOpen(false);
+ }}
+ sx={{
+ zIndex: '99999999',
+ marginRight: '15px',
+ backgroundColor: colorPalette.white,
+ }}
+ >
+
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.sortBy')}
+
+
+ {t('worker.jobs.rewardAmount')}
+
+
+
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'DESC',
+ sort_field: 'reward_amount',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ {t('worker.jobs.sortDirection.fromHighest')}
+
+
+
+
+
+
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'ASC',
+ sort_field: 'reward_amount',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ From lowest
+
+
+
+ {t('worker.jobs.expiresAt')}
+
+
+
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'DESC',
+ sort_field: 'expires_at',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ {t('worker.jobs.sortDirection.fromHighest')}
+
+
+
+
+
+
+ {
+ setFilterParams({
+ ...filterParams,
+ sort: 'ASC',
+ sort_field: 'expires_at',
+ });
+ }}
+ sx={{
+ marginLeft: '10px',
+ }}
+ variant="subtitle1"
+ >
+ From lowest
+
+
+
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {t('worker.jobs.network')}
+
+
+
+
+
+
+
+ {t('worker.jobs.jobType')}
+
+
+
+
+
+
+ {t('worker.jobs.status')}
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-job-type-filter-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-job-type-filter-mobile.tsx
new file mode 100644
index 0000000000..e2b7fb7921
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-job-type-filter-mobile.tsx
@@ -0,0 +1,36 @@
+/* eslint-disable camelcase --- ... */
+import capitalize from 'lodash/capitalize';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+import { stringToUpperSnakeCase } from '@/shared/helpers/string-to-upper-snake-case';
+
+export function MyJobsJobTypeFilter({ jobTypes }: { jobTypes: string[] }) {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ job_type: undefined,
+ page: 0,
+ });
+ }}
+ filteringOptions={jobTypes.map((jobType) => ({
+ name: capitalize(jobType),
+ option: jobType.toLowerCase(),
+ }))}
+ isChecked={(option) =>
+ stringToUpperSnakeCase(option) === filterParams.job_type
+ }
+ isMobile={false}
+ setFiltering={(jobType) => {
+ setFilterParams({
+ ...filterParams,
+ job_type: stringToUpperSnakeCase(jobType),
+ page: 0,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-network-filter-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-network-filter-mobile.tsx
new file mode 100644
index 0000000000..0386c43dc5
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-network-filter-mobile.tsx
@@ -0,0 +1,35 @@
+/* eslint-disable camelcase --- ... */
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { chains } from '@/smart-contracts/chains';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+
+const allNetworks = chains.map(({ chainId, name }) => ({
+ option: chainId,
+ name,
+}));
+
+export function MyJobsNetworkFilter() {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ chain_id: undefined,
+ page: 0,
+ });
+ }}
+ filteringOptions={allNetworks}
+ isChecked={(option) => option === filterParams.chain_id}
+ isMobile={false}
+ setFiltering={(chainId) => {
+ setFilterParams({
+ ...filterParams,
+ chain_id: chainId,
+ page: 0,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-status-filter-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-status-filter-mobile.tsx
new file mode 100644
index 0000000000..2be4207513
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-status-filter-mobile.tsx
@@ -0,0 +1,34 @@
+import capitalize from 'lodash/capitalize';
+import {
+ jobStatuses,
+ useMyJobsFilterStore,
+} from '@/hooks/use-my-jobs-filter-store';
+import { Filtering } from '@/components/ui/table/table-header-menu.tsx/filtering';
+
+export function MyJobsStatusFilter() {
+ const { setFilterParams, filterParams } = useMyJobsFilterStore();
+
+ return (
+ {
+ setFilterParams({
+ ...filterParams,
+ status: undefined,
+ page: 0,
+ });
+ }}
+ filteringOptions={jobStatuses.map((status) => ({
+ name: capitalize(status),
+ option: status,
+ }))}
+ isChecked={(status) => status === filterParams.status}
+ setFiltering={(status) => {
+ setFilterParams({
+ ...filterParams,
+ status,
+ page: 0,
+ });
+ }}
+ />
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-table-mobile.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-table-mobile.tsx
new file mode 100644
index 0000000000..09603abe2d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/mobile/my-jobs-table-mobile.tsx
@@ -0,0 +1,192 @@
+/* eslint-disable camelcase -- ... */
+import { Grid, List, Paper, Stack, Typography } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { useEffect, useState, type Dispatch, type SetStateAction } from 'react';
+import { Link, useParams } from 'react-router-dom';
+import { colorPalette } from '@/styles/color-palette';
+import { Button } from '@/components/ui/button';
+import { SearchForm } from '@/pages/playground/table-example/table-search-form';
+import { FiltersButtonIcon } from '@/components/ui/icons';
+import { formatDate } from '@/shared/helpers/format-date';
+import { Loader } from '@/components/ui/loader';
+import { Alert } from '@/components/ui/alert';
+import { getNetworkName } from '@/smart-contracts/get-network-name';
+import { TableButton } from '@/components/ui/table-button';
+import { useJobsFilterStore } from '@/hooks/use-jobs-filter-store';
+import { RejectButton } from '@/pages/worker/jobs/components/reject-button';
+import { useRejectTaskMutation } from '@/api/servieces/worker/reject-task';
+import type { MyJob } from '@/api/servieces/worker/my-jobs-data';
+import { useInfiniteGetMyJobsData } from '@/api/servieces/worker/my-jobs-data';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { useMyJobsFilterStore } from '@/hooks/use-my-jobs-filter-store';
+import { ListItem } from '@/components/ui/list-item';
+import { EvmAddress } from '@/pages/worker/jobs/components/evm-address';
+import { RewardAmount } from '@/pages/worker/jobs/components/reward-amount';
+import { Chips } from '@/components/ui/chips';
+
+interface MyJobsTableMobileProps {
+ setIsMobileFilterDrawerOpen: Dispatch>;
+}
+
+export function MyJobsTableMobile({
+ setIsMobileFilterDrawerOpen,
+}: MyJobsTableMobileProps) {
+ const [allPages, setAllPages] = useState([]);
+ const { filterParams, setPageParams } = useMyJobsFilterStore();
+
+ const { t } = useTranslation();
+ const {
+ data: tableData,
+ status: tableStatus,
+ isError: isTableError,
+ error: tableError,
+ fetchNextPage,
+ hasNextPage,
+ } = useInfiniteGetMyJobsData();
+
+ const { mutate: rejectTaskMutation } = useRejectTaskMutation();
+ const { setSearchEscrowAddress } = useJobsFilterStore();
+ const { address: oracle_address } = useParams<{ address: string }>();
+
+ useEffect(() => {
+ if (!tableData) return;
+ const pagesFromRes = tableData.pages.flatMap((pages) => pages.results);
+ if (filterParams.page === 0) {
+ setAllPages(pagesFromRes);
+ } else {
+ setAllPages((state) => [...state, ...pagesFromRes]);
+ }
+ }, [tableData, filterParams.page]);
+
+ return (
+ <>
+
+ {
+ setIsMobileFilterDrawerOpen(true);
+ }}
+ sx={{
+ marginBottom: '32px',
+ marginTop: '21px',
+ }}
+ variant="outlined"
+ >
+ {t('worker.jobs.mobileFilterDrawer.filters')}
+
+
+
+ {isTableError ? (
+
+ {defaultErrorMessage(tableError)}
+
+ ) : null}
+ {tableStatus === 'pending' ? (
+
+
+
+ ) : null}
+ {allPages.map((d) => {
+ const buttonDisabled = d.status !== 'ACTIVE';
+ return (
+
+
+
+
+
+
+
+
+
+ {d.expires_at ? formatDate(d.expires_at) : ''}
+
+
+
+
+
+
+
+
+
+ {getNetworkName()}
+
+
+
+
+
+
+
+
+
+
+
+ {t('worker.jobs.solve')}
+
+ {
+ if (buttonDisabled) return;
+ rejectTaskMutation({
+ oracle_address: oracle_address || '',
+ assignment_id: d.assignment_id,
+ });
+ }}
+ />
+
+
+
+
+ );
+ })}
+ {hasNextPage ? (
+ {
+ setPageParams(filterParams.page + 1, filterParams.page_size);
+ void fetchNextPage();
+ }}
+ variant="outlined"
+ >
+ {t('worker.jobs.next')}
+
+ ) : null}
+
+ >
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/parse-job-status-chip-color.ts b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/parse-job-status-chip-color.ts
new file mode 100644
index 0000000000..6fc5021cdd
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/my-jobs/parse-job-status-chip-color.ts
@@ -0,0 +1,14 @@
+import { colorPalette } from '@/styles/color-palette';
+
+export const parseJobStatusChipColor = (status: string) => {
+ if (status === 'OVERDUE') {
+ return colorPalette.error.main;
+ }
+ if (status === 'DEACTIVATED') {
+ return colorPalette.error.dark;
+ }
+ if (status === 'COMPLETED') {
+ return colorPalette.success.main;
+ }
+ return colorPalette.primary.light;
+};
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/reject-button.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/reject-button.tsx
new file mode 100644
index 0000000000..1d3934cdfe
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/reject-button.tsx
@@ -0,0 +1,29 @@
+import CloseIcon from '@mui/icons-material/Close';
+import type { CustomButtonProps } from '@/components/ui/button';
+import { TableButton } from '@/components/ui/table-button';
+import { colorPalette } from '@/styles/color-palette';
+
+export function RejectButton(props: CustomButtonProps) {
+ return (
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/reward-amount.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/reward-amount.tsx
new file mode 100644
index 0000000000..2c4355c987
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/reward-amount.tsx
@@ -0,0 +1,28 @@
+/* eslint-disable camelcase -- ...*/
+import Tooltip from '@mui/material/Tooltip';
+import Typography from '@mui/material/Typography';
+
+export function RewardAmount({
+ reward_amount,
+ reward_token,
+ color,
+}: {
+ reward_amount?: number;
+ reward_token?: string;
+ color?: string;
+}) {
+ if (!(reward_amount !== undefined && reward_token)) {
+ return '';
+ }
+ const hasDecimals = reward_amount - Math.floor(reward_amount) !== 0;
+ if (hasDecimals) {
+ return (
+
+
+ {`${reward_amount.toFixed(2)} ${reward_token}`}
+
+
+ );
+ }
+ return `${reward_amount} ${reward_token}`;
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/components/text-header-with-icon.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/text-header-with-icon.tsx
new file mode 100644
index 0000000000..fd35c111aa
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/components/text-header-with-icon.tsx
@@ -0,0 +1,35 @@
+import Grid from '@mui/material/Grid/Grid';
+import { FilersIcon } from '@/components/ui/icons';
+
+export type IconType = 'filter';
+
+export function TextHeaderWithIcon({
+ text,
+ iconType,
+}: {
+ text: string;
+ iconType: IconType;
+}) {
+ const getIcon = () => {
+ switch (iconType) {
+ case 'filter':
+ return ;
+ }
+ };
+
+ return (
+
+ {text}
+ {getIcon()}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/jobs/jobs.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/jobs/jobs.page.tsx
new file mode 100644
index 0000000000..6581f05c93
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/jobs/jobs.page.tsx
@@ -0,0 +1,133 @@
+import React, { useState, useEffect } from 'react';
+import { Box, Grid, Paper, Stack, Tab, Tabs } from '@mui/material';
+import { useTranslation } from 'react-i18next';
+import { TableQueryContextProvider } from '@/components/ui/table/table-query-context';
+import { colorPalette } from '@/styles/color-palette';
+import { useBackgroundColorStore } from '@/hooks/use-background-store';
+import { Modal } from '@/components/ui/modal/modal';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+import { MyJobsTableMobile } from '@/pages/worker/jobs/components/my-jobs/mobile/my-jobs-table-mobile';
+import { AvailableJobsTable } from '@/pages/worker/jobs/components/available-jobs/desktop/available-jobs-table';
+import { MyJobsDrawerMobile } from '@/pages/worker/jobs/components/my-jobs/mobile/my-jobs-drawer-mobile';
+import { AvailableJobsDrawerMobile } from '@/pages/worker/jobs/components/available-jobs/mobile/available-jobs-drawer-mobile';
+import { AvailableJobsTableMobile } from './components/available-jobs/mobile/available-jobs-table-mobile';
+import { TabPanel } from './components/jobs-tab-panel';
+import { MyJobsTable } from './components/my-jobs/desktop/my-jobs-table';
+
+function generateTabA11yProps(index: number) {
+ return {
+ id: `tab-${index}`,
+ 'aria-controls': `jobs-tabpanel-${index}`,
+ };
+}
+
+export function JobsPage() {
+ const { setGrayBackground } = useBackgroundColorStore();
+ const { t } = useTranslation();
+ const [activeTab, setActiveTab] = useState(0);
+ const isMobile = useIsMobile();
+ const [selectedTab, setSelectedTab] = useState<'availableJobs' | 'myJobs'>(
+ 'availableJobs'
+ );
+ const [isMobileFilterDrawerOpen, setIsMobileFilterDrawerOpen] =
+ useState(false);
+
+ const handleTabChange = (_event: React.SyntheticEvent, newValue: number) => {
+ setActiveTab(newValue);
+ if (newValue === 0) {
+ setSelectedTab('availableJobs');
+ }
+ if (newValue === 1) {
+ setSelectedTab('myJobs');
+ }
+ };
+
+ useEffect(() => {
+ setGrayBackground();
+ }, [setGrayBackground]);
+
+ return (
+ <>
+
+ {selectedTab === 'availableJobs' ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {isMobile ? (
+
+ ) : null}
+ {!isMobile ? : null}
+
+
+ <>
+ {isMobile ? (
+
+ ) : null}
+ {!isMobile ? : null}
+ >
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/done-label.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/done-label.tsx
new file mode 100644
index 0000000000..7495d65899
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/done-label.tsx
@@ -0,0 +1,20 @@
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import { CheckmarkIcon } from '@/components/ui/icons';
+
+interface DoneLabelProps {
+ children: string | React.ReactElement;
+}
+
+export function DoneLabel({ children }: DoneLabelProps) {
+ if (typeof children === 'string') {
+ return (
+
+ {children}
+
+
+ );
+ }
+
+ return children;
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/profile-actions.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/profile-actions.tsx
new file mode 100644
index 0000000000..526d37da09
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/profile-actions.tsx
@@ -0,0 +1,113 @@
+import Grid from '@mui/material/Grid';
+import { useTranslation } from 'react-i18next';
+import { Navigate } from 'react-router-dom';
+import { useEffect, useRef } from 'react';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+import { Button } from '@/components/ui/button';
+import { routerPaths } from '@/router/router-paths';
+import { WalletConnectDone } from '@/pages/worker/profile/wallet-connect-done';
+import { StartKycButton } from '@/pages/worker/profile/start-kyc-btn';
+import { RegisterAddressBtn } from '@/pages/worker/profile/register-address-btn';
+import { DoneLabel } from '@/pages/worker/profile/done-label';
+import { useRegisterAddressNotifications } from '@/hooks/use-register-address-notifications';
+import { useRegisterAddressMutation } from '@/api/servieces/worker/use-register-address';
+import { RegisterAddressOnChainButton } from '@/pages/worker/profile/register-address-on-chain-btn';
+
+export function ProfileActions() {
+ const {
+ isConnected: isWalletConnected,
+ address,
+ openModal,
+ } = useWalletConnect();
+ const { onSuccess, onError } = useRegisterAddressNotifications();
+ const {
+ mutate: registerAddressMutation,
+ isPending: isRegisterAddressMutationPending,
+ } = useRegisterAddressMutation({
+ onError,
+ onSuccess,
+ });
+ const modalWasOpened = useRef(false);
+ useEffect(() => {
+ if (isWalletConnected && modalWasOpened.current) {
+ registerAddressMutation();
+ }
+ }, [address, isWalletConnected, registerAddressMutation]);
+ const { user } = useAuthenticatedUser();
+ const { t } = useTranslation();
+ const emailVerified = user.status === 'ACTIVE';
+ const kycApproved = user.kyc_status === 'APPROVED';
+
+ const getConnectWalletBtn = () => {
+ switch (true) {
+ case !kycApproved:
+ return (
+
+ {t('components.wallet.connectBtn.connect')}
+
+ );
+ case !user.wallet_address && isWalletConnected:
+ case Boolean(user.wallet_address):
+ return (
+
+
+
+ );
+ case !user.wallet_address && !isWalletConnected:
+ return (
+ {
+ modalWasOpened.current = true;
+ void openModal();
+ }}
+ variant="contained"
+ >
+ {t('components.wallet.connectBtn.connect')}
+
+ );
+ default:
+ return null;
+ }
+ };
+
+ if (!emailVerified) {
+ return (
+
+ );
+ }
+
+ return (
+
+
+ {kycApproved ? (
+ {t('worker.profile.kycCompleted')}
+ ) : (
+
+ )}
+
+ {getConnectWalletBtn()}
+ {kycApproved && !user.wallet_address && isWalletConnected ? (
+
+
+
+ ) : null}
+
+ {kycApproved && user.wallet_address ? (
+
+ ) : (
+
+ {t('worker.profile.addKYCInfoOnChain')}
+
+ )}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/profile-data.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/profile-data.tsx
new file mode 100644
index 0000000000..eba1565455
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/profile-data.tsx
@@ -0,0 +1,39 @@
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import { useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+import { colorPalette } from '@/styles/color-palette';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { Button } from '@/components/ui/button';
+import { routerPaths } from '@/router/router-paths';
+
+export function ProfileData() {
+ const { user } = useAuthenticatedUser();
+ const { t } = useTranslation();
+ return (
+
+
+ {t('worker.profile.email')}
+
+ {user.email}
+
+
+
+
+ {t('worker.profile.resetPassword')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/profile-email-notifications.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/profile-email-notifications.tsx
new file mode 100644
index 0000000000..d6b0cdcd24
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/profile-email-notifications.tsx
@@ -0,0 +1,25 @@
+import Grid from '@mui/material/Grid';
+import { useTranslation } from 'react-i18next';
+import Typography from '@mui/material/Typography';
+import Stack from '@mui/material/Stack';
+import Switch from '@mui/material/Switch';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+
+export function ProfileEmailNotification() {
+ const { user } = useAuthenticatedUser();
+ const { t } = useTranslation();
+
+ return (
+
+
+ {t('worker.profile.emailNotifications')}
+
+
+
+ {t('worker.profile.notificationsConsent')}
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/profile.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/profile.page.tsx
new file mode 100644
index 0000000000..35314c1709
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/profile.page.tsx
@@ -0,0 +1,79 @@
+import { Grid, Paper } from '@mui/material';
+import { useEffect } from 'react';
+import { t } from 'i18next';
+import { colorPalette } from '@/styles/color-palette';
+import { ProfileData } from '@/pages/worker/profile/profile-data';
+import { ProfileActions } from '@/pages/worker/profile/profile-actions';
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import type { UserData } from '@/auth/auth-context';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+import { useBackgroundColorStore } from '@/hooks/use-background-store';
+import { useIsMobile } from '@/hooks/use-is-mobile';
+
+const getNotificationMessage = (
+ user: UserData & { isWalletConnected: boolean }
+) => {
+ switch (true) {
+ case user.kyc_status !== 'APPROVED':
+ return t('worker.profile.topNotifications.noKYC');
+ case user.kyc_status === 'APPROVED' && !user.wallet_address:
+ return t('worker.profile.topNotifications.registerAddress');
+ default:
+ return null;
+ }
+};
+
+export function WorkerProfilePage() {
+ const isMobile = useIsMobile();
+ const { user } = useAuthenticatedUser();
+ const { isConnected } = useWalletConnect();
+ const { setGrayBackground } = useBackgroundColorStore();
+ const { setTopNotification: setTopNotificationInLayout } =
+ useProtectedLayoutNotification();
+
+ const setNotifications = () => {
+ const notification = getNotificationMessage({
+ ...user,
+ isWalletConnected: isConnected,
+ });
+ if (notification) {
+ setTopNotificationInLayout({ type: 'warning', content: notification });
+ }
+ };
+
+ useEffect(() => {
+ setNotifications();
+ setGrayBackground();
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- call this once
+ }, [isConnected]);
+
+ return (
+
+
+
+
+ {/* TODO add email notifications toggling */}
+ {/* */}
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/register-address-btn.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/register-address-btn.tsx
new file mode 100644
index 0000000000..0ba1c18f8c
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/register-address-btn.tsx
@@ -0,0 +1,23 @@
+import { t } from 'i18next';
+import { Button } from '@/components/ui/button';
+import { useRegisterAddressMutation } from '@/api/servieces/worker/use-register-address';
+import { useRegisterAddressNotifications } from '@/hooks/use-register-address-notifications';
+
+export function RegisterAddressBtn() {
+ const { onSuccess, onError } = useRegisterAddressNotifications();
+ const { mutate, isPending } = useRegisterAddressMutation({
+ onError,
+ onSuccess,
+ });
+
+ return (
+
+ {t('worker.profile.registerAddress')}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/register-address-on-chain-btn.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/register-address-on-chain-btn.tsx
new file mode 100644
index 0000000000..78ef68b7b9
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/register-address-on-chain-btn.tsx
@@ -0,0 +1,111 @@
+import { t } from 'i18next';
+import { useEffect, useRef } from 'react';
+import { Button } from '@/components/ui/button';
+import { useGetOnChainRegisteredAddress } from '@/api/servieces/worker/get-on-chain-registered-address';
+import { useGetSignedAddress } from '@/api/servieces/worker/get-signed-address';
+import { useRegisterAddressOnChainMutation } from '@/api/servieces/worker/use-register-address-on-chain';
+import { DoneLabel } from '@/pages/worker/profile/done-label';
+import { useProtectedLayoutNotification } from '@/hooks/use-protected-layout-notifications';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+
+export function RegisterAddressOnChainButton() {
+ const { setTopNotification, closeNotification } =
+ useProtectedLayoutNotification();
+ const { isConnected: isWalletConnected, openModal } = useWalletConnect();
+ const modalWasOpened = useRef(false);
+
+ const {
+ data: onChainRegisteredAddress,
+ isError: inOnChainRegisteredAddressError,
+ error: onChainRegisteredAddressError,
+ isPending: isOnChainRegisteredAddressPending,
+ } = useGetOnChainRegisteredAddress();
+
+ const {
+ data: signedAddress,
+ isError: isSignedAddressError,
+ error: signedAddressError,
+ isPending: isSignedAddressPending,
+ } = useGetSignedAddress();
+
+ const {
+ mutate: registerAddressOnChainMutation,
+ isError: isRegisterAddressOnChainError,
+ error: registerAddressOnChainError,
+ isPending: isRegisterAddressOnChainPending,
+ } = useRegisterAddressOnChainMutation();
+
+ const isPending =
+ isOnChainRegisteredAddressPending ||
+ isSignedAddressPending ||
+ isRegisterAddressOnChainPending;
+
+ const isError =
+ inOnChainRegisteredAddressError ||
+ isSignedAddressError ||
+ isRegisterAddressOnChainError;
+
+ const error =
+ onChainRegisteredAddressError ||
+ signedAddressError ||
+ registerAddressOnChainError;
+
+ const isAddressSetInKVStore =
+ onChainRegisteredAddress === signedAddress?.value;
+
+ useEffect(() => {
+ if (isError) {
+ setTopNotification({
+ type: 'warning',
+ content: defaultErrorMessage(error),
+ });
+ return;
+ }
+ closeNotification();
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- ...
+ }, [error, isError]);
+
+ useEffect(() => {
+ if (isWalletConnected && modalWasOpened.current && signedAddress) {
+ registerAddressOnChainMutation(signedAddress);
+ }
+ }, [isWalletConnected, registerAddressOnChainMutation, signedAddress]);
+
+ if (isPending) {
+ return (
+
+ {t('worker.profile.addKYCInfoOnChain')}
+
+ );
+ }
+
+ if (isError) {
+ return (
+
+ {t('worker.profile.addKYCInfoOnChain')}
+
+ );
+ }
+
+ if (isAddressSetInKVStore) {
+ return {t('worker.profile.kycInfoOnChainAdded')} ;
+ }
+
+ return (
+ {
+ if (isWalletConnected) {
+ registerAddressOnChainMutation(signedAddress);
+ } else {
+ modalWasOpened.current = true;
+ void openModal();
+ }
+ }}
+ variant="contained"
+ >
+ {t('worker.profile.addKYCInfoOnChain')}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/start-kyc-btn.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/start-kyc-btn.tsx
new file mode 100644
index 0000000000..f94bb80e34
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/start-kyc-btn.tsx
@@ -0,0 +1,70 @@
+import { t } from 'i18next';
+import { useEffect, useState } from 'react';
+import { useKycSessionIdMutation } from '@/api/servieces/worker/get-kyc-session-id';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { Button } from '@/components/ui/button';
+import { startSynapsKyc } from '@/pages/worker/profile/start-synaps-kyc';
+import { useKycErrorNotifications } from '@/hooks/use-kyc-notification';
+import { FetchError } from '@/api/fetcher';
+
+export function StartKycButton() {
+ const [isKYCInProgress, setIsKYCInProgress] = useState(false);
+ const { user } = useAuthenticatedUser();
+ const onError = useKycErrorNotifications();
+ const {
+ data: kycSessionIdData,
+ isPending: kycSessionIdIsPending,
+ mutate: kycSessionIdMutation,
+ status: kycSessionIdMutationStatus,
+ error: kycSessionIdMutationError,
+ } = useKycSessionIdMutation();
+
+ const startKYC = () => {
+ kycSessionIdMutation();
+ };
+
+ useEffect(() => {
+ if (kycSessionIdMutationStatus === 'error') {
+ if (
+ kycSessionIdMutationError instanceof FetchError &&
+ kycSessionIdMutationError.status === 400
+ ) {
+ setIsKYCInProgress(true);
+ return;
+ }
+ onError(kycSessionIdMutationError);
+ }
+
+ if (
+ kycSessionIdMutationStatus === 'success' &&
+ kycSessionIdData.session_id
+ ) {
+ startSynapsKyc(kycSessionIdData.session_id);
+ }
+ }, [
+ kycSessionIdData?.session_id,
+ kycSessionIdMutationError,
+ kycSessionIdMutationStatus,
+ onError,
+ ]);
+
+ if (isKYCInProgress) {
+ return (
+
+ {t('worker.profile.KYCInProgress')}
+
+ );
+ }
+
+ return (
+
+ {t('worker.profile.completeKYC')}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/start-synaps-kyc.ts b/packages/apps/human-app/frontend/src/pages/worker/profile/start-synaps-kyc.ts
new file mode 100644
index 0000000000..e42cad56d7
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/start-synaps-kyc.ts
@@ -0,0 +1,9 @@
+import { Synaps } from '@synaps-io/verify-sdk';
+
+export function startSynapsKyc(sessionId: string) {
+ Synaps.init({
+ sessionId,
+ mode: 'modal',
+ });
+ Synaps.show();
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/profile/wallet-connect-done.tsx b/packages/apps/human-app/frontend/src/pages/worker/profile/wallet-connect-done.tsx
new file mode 100644
index 0000000000..54c905ce45
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/profile/wallet-connect-done.tsx
@@ -0,0 +1,35 @@
+import Grid from '@mui/material/Grid/Grid';
+import TextField from '@mui/material/TextField';
+import Typography from '@mui/material/Typography/Typography';
+import { t } from 'i18next';
+import styled from '@mui/material/styles/styled';
+import { CheckmarkIcon } from '@/components/ui/icons';
+import { colorPalette } from '@/styles/color-palette';
+import { useAuthenticatedUser } from '@/auth/use-authenticated-user';
+import { useWalletConnect } from '@/hooks/use-wallet-connect';
+
+const CustomTextField = styled(TextField)(() => ({
+ '& .Mui-disabled': {
+ color: colorPalette.text.disabledSecondary,
+ '-webkit-text-fill-color': colorPalette.text.disabledSecondary,
+ },
+}));
+
+export function WalletConnectDone() {
+ const { address } = useWalletConnect();
+ const { user } = useAuthenticatedUser();
+
+ return (
+
+
+ {t('worker.profile.walletConnected')}
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/reset-password/reset-password-success.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/reset-password/reset-password-success.page.tsx
new file mode 100644
index 0000000000..a3893ad7aa
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/reset-password/reset-password-success.page.tsx
@@ -0,0 +1,51 @@
+import Grid from '@mui/material/Grid';
+import { t } from 'i18next';
+import { Link } from 'react-router-dom';
+import Typography from '@mui/material/Typography';
+import CheckCircle from '@mui/icons-material/CheckCircle';
+import { useEffect } from 'react';
+import { Button } from '@/components/ui/button';
+import { routerPaths } from '@/router/router-paths';
+import { PageCard } from '@/components/ui/page-card';
+import { colorPalette } from '@/styles/color-palette';
+import { useAuth } from '@/auth/use-auth';
+
+export function ResetPasswordWorkerSuccessPage() {
+ const { signOut } = useAuth();
+
+ useEffect(() => {
+ signOut();
+ }, [signOut]);
+ return (
+
+ {t('worker.resetPasswordSuccess.title')}
+
+
+ }
+ >
+
+
+ {t('worker.resetPasswordSuccess.description')}
+
+
+ {t('worker.resetPasswordSuccess.btn')}
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/reset-password/reset-password.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/reset-password/reset-password.page.tsx
new file mode 100644
index 0000000000..21cf5b47a5
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/reset-password/reset-password.page.tsx
@@ -0,0 +1,100 @@
+/* eslint-disable camelcase -- ... */
+import { FormProvider, useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import { t } from 'i18next';
+import omit from 'lodash/omit';
+import { useLocation } from 'react-router-dom';
+import queryString from 'query-string';
+import { Button } from '@/components/ui/button';
+import { Password } from '@/components/data-entry/password/password';
+import { PageCard } from '@/components/ui/page-card';
+import type { ResetPasswordDto } from '@/api/servieces/worker/reset-password';
+import {
+ resetPasswordDtoSchema,
+ useResetPasswordMutation,
+} from '@/api/servieces/worker/reset-password';
+import { Alert } from '@/components/ui/alert';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { passwordChecks } from '@/components/data-entry/password/password-checks';
+import { routerPaths } from '@/router/router-paths';
+import { FormCaptcha } from '@/components/h-captcha';
+
+export function ResetPasswordWorkerPage() {
+ const location = useLocation();
+ const { token } = queryString.parse(location.search);
+
+ const methods = useForm({
+ defaultValues: {
+ password: '',
+ confirmPassword: '',
+ h_captcha_token: '',
+ },
+ resolver: zodResolver(resetPasswordDtoSchema),
+ });
+
+ const {
+ mutate: resetPasswordWorkerMutate,
+ error: resetPasswordWorkerError,
+ isError: isResetPasswordWorkerError,
+ isPending: isResetPasswordWorkerPending,
+ } = useResetPasswordMutation();
+
+ const handleWorkerResetPassword = (data: ResetPasswordDto) => {
+ resetPasswordWorkerMutate(
+ omit({ ...data, token: token?.toString() || '' }, ['confirmPassword'])
+ );
+ };
+
+ return (
+
+ {defaultErrorMessage(resetPasswordWorkerError)}
+
+ ) : undefined
+ }
+ cancelRouterPathOrCallback={routerPaths.worker.profile}
+ hiddenCancelButton
+ title={t('worker.resetPassword.title')}
+ >
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/send-reset-link/send-reset-link-success.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/send-reset-link/send-reset-link-success.page.tsx
new file mode 100644
index 0000000000..301a8764f1
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/send-reset-link/send-reset-link-success.page.tsx
@@ -0,0 +1,112 @@
+/* eslint-disable camelcase -- ... */
+import { Grid, Typography } from '@mui/material';
+import { Trans, useTranslation } from 'react-i18next';
+import { Link } from 'react-router-dom';
+import { z } from 'zod';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { FormProvider, useForm } from 'react-hook-form';
+import { PageCard } from '@/components/ui/page-card';
+import { Button } from '@/components/ui/button';
+import { colorPalette } from '@/styles/color-palette';
+import { useLocationState } from '@/hooks/use-location-state';
+import { env } from '@/shared/env';
+import type { SendResetLinkHcaptcha } from '@/api/servieces/worker/send-reset-link';
+import {
+ sendResetLinkHcaptchaDtoSchema,
+ useSendResetLinkMutation,
+} from '@/api/servieces/worker/send-reset-link';
+import { Alert } from '@/components/ui/alert';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { FormCaptcha } from '@/components/h-captcha';
+
+export function SendResetLinkWorkerSuccessPage() {
+ const { t } = useTranslation();
+ const { field: email } = useLocationState({
+ keyInStorage: 'email',
+ schema: z.string().email(),
+ });
+ const { mutate, error, isError, isPending } = useSendResetLinkMutation();
+
+ const handleWorkerSendResetLink = (dto: SendResetLinkHcaptcha) => {
+ mutate({ ...dto, email: email || '' });
+ };
+
+ const methods = useForm({
+ defaultValues: {
+ h_captcha_token: '',
+ },
+ resolver: zodResolver(sendResetLinkHcaptchaDtoSchema),
+ });
+
+ return (
+
+ {defaultErrorMessage(error)}
+
+ ) : undefined
+ }
+ title={t('worker.sendResetLinkForm.title')}
+ >
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/send-reset-link/send-reset-link.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/send-reset-link/send-reset-link.page.tsx
new file mode 100644
index 0000000000..4394ae5ded
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/send-reset-link/send-reset-link.page.tsx
@@ -0,0 +1,87 @@
+/* eslint-disable camelcase -- ...*/
+import { FormProvider, useForm } from 'react-hook-form';
+import { Grid, Typography } from '@mui/material';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useTranslation } from 'react-i18next';
+import { PageCard } from '@/components/ui/page-card';
+import { Input } from '@/components/data-entry/input';
+import { Button } from '@/components/ui/button';
+import type { SendResetLinkDto } from '@/api/servieces/worker/send-reset-link';
+import {
+ sendResetLinkDtoSchema,
+ useSendResetLinkMutation,
+} from '@/api/servieces/worker/send-reset-link';
+import { Alert } from '@/components/ui/alert';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { useAuth } from '@/auth/use-auth';
+import { FormCaptcha } from '@/components/h-captcha';
+import { routerPaths } from '@/router/router-paths';
+
+export function SendResetLinkWorkerPage() {
+ const { t } = useTranslation();
+ const { user } = useAuth();
+
+ const methods = useForm({
+ defaultValues: {
+ email: user?.email || '',
+ h_captcha_token: '',
+ },
+ resolver: zodResolver(sendResetLinkDtoSchema),
+ });
+
+ const {
+ mutate: sendResetLinkWorkerMutate,
+ error: sendResetLinkWorkerError,
+ isError: isSendResetLinkWorkerError,
+ isPending: isSendResetLinkWorkerPending,
+ } = useSendResetLinkMutation();
+
+ function handleWorkerSendResetLink(data: SendResetLinkDto) {
+ sendResetLinkWorkerMutate(data);
+ }
+
+ return (
+
+ {defaultErrorMessage(sendResetLinkWorkerError)}
+
+ ) : undefined
+ }
+ cancelRouterPathOrCallback={routerPaths.worker.profile}
+ title={t('worker.sendResetLinkForm.title')}
+ >
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/sign-in.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/sign-in.page.tsx
new file mode 100644
index 0000000000..8e169c2743
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/sign-in.page.tsx
@@ -0,0 +1,114 @@
+import { FormProvider, useForm } from 'react-hook-form';
+import { Grid, Typography } from '@mui/material';
+import { zodResolver } from '@hookform/resolvers/zod';
+import { useTranslation } from 'react-i18next';
+import { t as i18NextT } from 'i18next';
+import { Link } from 'react-router-dom';
+import { useEffect } from 'react';
+import { PageCard } from '@/components/ui/page-card';
+import { Input } from '@/components/data-entry/input';
+import { Button } from '@/components/ui/button';
+import { Password } from '@/components/data-entry/password/password';
+import type { SignInDto } from '@/api/servieces/worker/sign-in';
+import {
+ signInDtoSchema,
+ useSignInMutation,
+} from '@/api/servieces/worker/sign-in';
+import { FetchError } from '@/api/fetcher';
+import { routerPaths } from '@/router/router-paths';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { Alert } from '@/components/ui/alert';
+import { useAuth } from '@/auth/use-auth';
+import { FormCaptcha } from '@/components/h-captcha';
+
+function formattedSignInErrorMessage(unknownError: unknown) {
+ if (unknownError instanceof FetchError && unknownError.status === 400) {
+ return i18NextT('worker.signInForm.errors.invalidCredentials');
+ }
+}
+
+export function SignInWorkerPage() {
+ const { t } = useTranslation();
+ const { user, signOut } = useAuth();
+
+ useEffect(() => {
+ if (user) {
+ signOut();
+ }
+ }, [signOut, user]);
+
+ const methods = useForm({
+ defaultValues: {
+ email: '',
+ password: '',
+ // eslint-disable-next-line camelcase -- export vite config
+ h_captcha_token: '',
+ },
+ resolver: zodResolver(signInDtoSchema),
+ });
+
+ const {
+ mutate: signInWorkerMutate,
+ error: signInWorkerError,
+ isError: isSignInWorkerError,
+ isPending: isSignInWorkerPending,
+ } = useSignInMutation();
+
+ function handleWorkerSignIn(data: SignInDto) {
+ signInWorkerMutate(data);
+ }
+
+ return (
+
+ {defaultErrorMessage(
+ signInWorkerError,
+ formattedSignInErrorMessage
+ )}
+
+ ) : undefined
+ }
+ title={t('worker.signInForm.title')}
+ >
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/pages/worker/sign-up.page.tsx b/packages/apps/human-app/frontend/src/pages/worker/sign-up.page.tsx
new file mode 100644
index 0000000000..65ccd68a77
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/pages/worker/sign-up.page.tsx
@@ -0,0 +1,119 @@
+import { Trans } from 'react-i18next';
+import { FormProvider, useForm } from 'react-hook-form';
+import { zodResolver } from '@hookform/resolvers/zod';
+import Grid from '@mui/material/Grid';
+import Typography from '@mui/material/Typography';
+import Link from '@mui/material/Link';
+import { t } from 'i18next';
+import omit from 'lodash/omit';
+import { useEffect } from 'react';
+import type { SignUpDto } from '@/api/servieces/worker/sign-up';
+import {
+ signUpDtoSchema,
+ useSignUpMutation,
+} from '@/api/servieces/worker/sign-up';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/data-entry/input';
+import { Password } from '@/components/data-entry/password/password';
+import { PageCard } from '@/components/ui/page-card';
+import { env } from '@/shared/env';
+import { defaultErrorMessage } from '@/shared/helpers/default-error-message';
+import { Alert } from '@/components/ui/alert';
+import { FetchError } from '@/api/fetcher';
+import { passwordChecks } from '@/components/data-entry/password/password-checks';
+import { useAuth } from '@/auth/use-auth';
+import { FormCaptcha } from '@/components/h-captcha';
+
+function formattedSignUpErrorMessage(unknownError: unknown) {
+ if (unknownError instanceof FetchError && unknownError.status === 409) {
+ return t('worker.signUpForm.errors.emailTaken');
+ }
+}
+
+export function SignUpWorkerPage() {
+ const { user, signOut } = useAuth();
+
+ useEffect(() => {
+ if (user) {
+ signOut();
+ }
+ }, [signOut, user]);
+
+ const methods = useForm({
+ defaultValues: {
+ email: '',
+ password: '',
+ confirmPassword: '',
+ // eslint-disable-next-line camelcase -- export vite config
+ h_captcha_token: '',
+ },
+ resolver: zodResolver(signUpDtoSchema),
+ });
+
+ const {
+ mutate: signUpWorkerMutate,
+ error: signUpWorkerError,
+ isError: isSignUpWorkerError,
+ isPending: isSignUpWorkerPending,
+ } = useSignUpMutation();
+
+ const handleWorkerSignUp = (data: SignUpDto) => {
+ signUpWorkerMutate(omit(data, ['confirmPassword']));
+ };
+
+ return (
+
+ {defaultErrorMessage(
+ signUpWorkerError,
+ formattedSignUpErrorMessage
+ )}
+
+ ) : undefined
+ }
+ title={t('worker.signUpForm.title')}
+ >
+
+
+
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/router/router-paths.ts b/packages/apps/human-app/frontend/src/router/router-paths.ts
new file mode 100644
index 0000000000..602e932f46
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/router/router-paths.ts
@@ -0,0 +1,28 @@
+export const routerPaths = {
+ homePage: '/',
+ playground: '/playground',
+ worker: {
+ signIn: '/worker/sign-in',
+ signUp: '/worker/sign-up',
+ resetPassword: '/reset-password',
+ resetPasswordSuccess: '/worker/reset-password-success',
+ sendResetLink: '/worker/send-reset-link',
+ sendResetLinkSuccess: '/worker/send-reset-link-success',
+ emailVerification: '/verify',
+ verifyEmail: '/worker/verify-email',
+ profile: '/worker/profile',
+ jobsDiscovery: '/worker/jobs-discovery',
+ jobs: '/worker/jobs',
+ HcaptchaLabeling: '/worker/hcaptcha-labeling',
+ enableLabeler: '/worker/enable-labeler',
+ },
+ operator: {
+ signIn: '/operator/sign-in',
+ connectWallet: '/operator/connect-wallet',
+ setUpOperator: '/operator/set-up',
+ addStake: '/operator/add-stake',
+ addKeys: '/operator/add-keys',
+ editExistingKeysSuccess: '/operator/edit-existing-keys-success',
+ profile: '/operator/profile',
+ },
+} as const;
diff --git a/packages/apps/human-app/frontend/src/router/router.tsx b/packages/apps/human-app/frontend/src/router/router.tsx
new file mode 100644
index 0000000000..ba9d846a70
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/router/router.tsx
@@ -0,0 +1,117 @@
+import { Routes, Route } from 'react-router-dom';
+import { Layout as LayoutProtected } from '@/components/layout/protected/layout';
+import { Layout as LayoutUnprotected } from '@/components/layout/unprotected/layout';
+import {
+ protectedRoutes,
+ walletConnectRoutes,
+ unprotectedRoutes,
+ web3ProtectedRoutes,
+} from '@/router/routes';
+import { RequireAuth } from '@/auth/require-auth';
+import { RequireWalletConnect } from '@/auth-web3/require-wallet-connect';
+import { RequireWeb3Auth } from '@/auth-web3/require-web3-auth';
+import { DrawerNavigation } from '@/components/layout/protected/drawer-navigation';
+import {
+ workerDrawerTopMenuItems,
+ workerDrawerBottomMenuItems,
+} from '@/components/layout/drawer-menu-items/drawer-menu-items-worker';
+import { operatorDrawerBottomMenuItems } from '@/components/layout/drawer-menu-items/drawer-menu-items-operator';
+import { browserAuthProvider } from '@/shared/helpers/browser-auth-provider';
+import { UserStatsDrawer } from '@/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-drawer';
+import { useAuth } from '@/auth/use-auth';
+
+export function Router() {
+ const { user } = useAuth();
+ return (
+
+ }>
+ {unprotectedRoutes.map((route) => (
+
+ ))}
+
+ }>
+ {walletConnectRoutes.map((route) => (
+
+ <>{route.element}>
+
+ }
+ key={route.path}
+ path={route.path}
+ />
+ ))}
+
+ {protectedRoutes.map(({ routerProps, pageHeaderProps }) => (
+ (
+ {
+ browserAuthProvider.signOut(() => {
+ window.location.reload();
+ });
+ }}
+ topMenuItems={workerDrawerTopMenuItems(
+ Boolean(user?.wallet_address)
+ )}
+ />
+ )}
+ renderHCaptchaStatisticsDrawer={(isOpen) => (
+
+ )}
+ />
+ }
+ key={routerProps.path}
+ >
+
+ <>{routerProps.element}>
+
+ }
+ path={routerProps.path}
+ />
+
+ ))}
+ {web3ProtectedRoutes.map(({ routerProps, pageHeaderProps }) => (
+ (
+ {
+ browserAuthProvider.signOut(() => {
+ window.location.reload();
+ });
+ }}
+ />
+ )}
+ />
+ }
+ key={routerProps.path}
+ >
+
+
+ <>{routerProps.element}>
+
+
+ }
+ path={routerProps.path}
+ />
+
+ ))}
+
+ );
+}
diff --git a/packages/apps/human-app/frontend/src/router/routes.tsx b/packages/apps/human-app/frontend/src/router/routes.tsx
new file mode 100644
index 0000000000..b5a25b9318
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/router/routes.tsx
@@ -0,0 +1,178 @@
+import type { RouteProps } from 'react-router-dom';
+import { t } from 'i18next';
+import { HomePage } from '@/pages/homepage/home.page';
+import { Playground } from '@/pages/playground/playground.page';
+import { ProtectedPage } from '@/pages/protected.page';
+import { SignInWorkerPage } from '@/pages/worker/sign-in.page';
+import { SignUpWorkerPage } from '@/pages/worker/sign-up.page';
+import { OperatorProfilePage } from '@/pages/operator/profile/profile.page';
+import { WorkerProfilePage } from '@/pages/worker/profile/profile.page';
+import { ConnectWalletOperatorPage } from '@/pages/operator/sign-up/connect-wallet.page';
+import { routerPaths } from '@/router/router-paths';
+import { AddStakeOperatorPage } from '@/pages/operator/sign-up/add-stake/add-stake.page';
+import { SendResetLinkWorkerSuccessPage } from '@/pages/worker/send-reset-link/send-reset-link-success.page';
+import { ResetPasswordWorkerPage } from '@/pages/worker/reset-password/reset-password.page';
+import { SendResetLinkWorkerPage } from '@/pages/worker/send-reset-link/send-reset-link.page';
+import { ResetPasswordWorkerSuccessPage } from '@/pages/worker/reset-password/reset-password-success.page';
+import { EmailVerificationWorkerPage } from '@/pages/worker/email-verification/email-verification.page';
+import { VerifyEmailWorkerPage } from '@/pages/worker/email-verification/verify-email.page';
+import { AddKeysOperatorPage } from '@/pages/operator/sign-up/add-keys/add-keys.page';
+import { EditExistingKeysSuccessPage } from '@/pages/operator/sign-up/add-keys/edit-existing-keys-success.page';
+import type { PageHeaderProps } from '@/components/layout/protected/page-header';
+import { HandIcon, HomepageWorkIcon, ProfileIcon } from '@/components/ui/icons';
+import { JobsDiscoveryPage } from '@/pages/worker/jobs-discovery/jobs-discovery.page';
+import { JobsPage } from '@/pages/worker/jobs/jobs.page';
+import { EnableLabeler } from '@/pages/worker/hcaptcha-labeling/enable-labeler.page';
+import { HcaptchaLabelingPage } from '@/pages/worker/hcaptcha-labeling/hcaptcha-labeling/hcaptcha-labeling.page';
+import { UserStatsAccordion } from '@/pages/worker/hcaptcha-labeling/hcaptcha-labeling/user-stats-accordion';
+import { SetUpOperatorPage } from '@/pages/operator/sign-up/set-up-operator';
+
+export const unprotectedRoutes: RouteProps[] = [
+ {
+ path: routerPaths.homePage,
+ element: ,
+ },
+ {
+ path: routerPaths.playground,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.signIn,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.signUp,
+ element: ,
+ },
+ {
+ path: routerPaths.operator.connectWallet,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.emailVerification,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.verifyEmail,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.sendResetLink,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.resetPassword,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.sendResetLinkSuccess,
+ element: ,
+ },
+ {
+ path: routerPaths.worker.resetPasswordSuccess,
+ element: ,
+ },
+];
+
+export const protectedRoutes: {
+ routerProps: RouteProps;
+ pageHeaderProps: PageHeaderProps;
+}[] = [
+ {
+ routerProps: {
+ path: '/protected',
+ element: ,
+ },
+ pageHeaderProps: {
+ headerIcon: ,
+ headerText: t('protectedPagesHeaders.profile'),
+ },
+ },
+ {
+ routerProps: {
+ path: routerPaths.worker.jobsDiscovery,
+ element: ,
+ },
+ pageHeaderProps: {
+ headerIcon: ,
+ headerText: t('protectedPagesHeaders.jobsDiscovery'),
+ },
+ },
+ {
+ routerProps: {
+ path: `${routerPaths.worker.jobs}/:address`,
+ element: ,
+ },
+ pageHeaderProps: {
+ headerIcon: ,
+ headerText: t('protectedPagesHeaders.jobs'),
+ },
+ },
+ {
+ routerProps: {
+ path: routerPaths.worker.profile,
+ element: ,
+ },
+ pageHeaderProps: {
+ headerIcon: ,
+ headerText: t('protectedPagesHeaders.profile'),
+ },
+ },
+ {
+ routerProps: {
+ path: routerPaths.worker.HcaptchaLabeling,
+ element: ,
+ },
+ pageHeaderProps: {
+ headerIcon: ,
+ headerText: t('protectedPagesHeaders.hcaptchaLabeling'),
+ headerItem: ,
+ },
+ },
+ {
+ routerProps: {
+ path: routerPaths.worker.enableLabeler,
+ element: ,
+ },
+ pageHeaderProps: {
+ headerIcon: ,
+ headerText: t('protectedPagesHeaders.hcaptchaLabeling'),
+ headerItem: ,
+ },
+ },
+];
+
+export const web3ProtectedRoutes: {
+ routerProps: RouteProps;
+ pageHeaderProps: PageHeaderProps;
+}[] = [
+ {
+ routerProps: {
+ path: routerPaths.operator.profile,
+ element: ,
+ },
+ pageHeaderProps: {
+ headerIcon: ,
+ headerText: t('web3ProtectedPagesHeaders.profile'),
+ },
+ },
+];
+
+export const walletConnectRoutes: RouteProps[] = [
+ {
+ path: routerPaths.operator.addStake,
+ element: ,
+ },
+ {
+ path: routerPaths.operator.addKeys,
+ element: ,
+ },
+ {
+ path: routerPaths.operator.editExistingKeysSuccess,
+ element: ,
+ },
+ {
+ path: routerPaths.operator.setUpOperator,
+ element: ,
+ },
+];
diff --git a/packages/apps/human-app/frontend/src/setup-tests.ts b/packages/apps/human-app/frontend/src/setup-tests.ts
new file mode 100644
index 0000000000..cd9d7dda1e
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/setup-tests.ts
@@ -0,0 +1,20 @@
+import * as matchers from '@testing-library/jest-dom/matchers';
+import { expect } from 'vitest';
+
+vi.mock('zustand');
+//Extends expect function with testing-library matchers
+expect.extend(matchers);
+
+//Mock for the i18 translation https://vitest.dev/api/vi#vi-importactual
+vi.mock('react-i18next', async () => {
+ const mod = await vi.importActual('react-i18next');
+ return {
+ ...mod,
+ useTranslation: () => {
+ return {
+ t: (str: string) => str,
+ i18n: vi.fn(),
+ };
+ },
+ };
+});
diff --git a/packages/apps/human-app/frontend/src/shared/consts.ts b/packages/apps/human-app/frontend/src/shared/consts.ts
new file mode 100644
index 0000000000..09255524bf
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/consts.ts
@@ -0,0 +1,3 @@
+import { JobTypes } from '@/smart-contracts/EthKVStore/config';
+
+export const JOB_TYPES = Object.values(JobTypes);
diff --git a/packages/apps/human-app/frontend/src/shared/env.ts b/packages/apps/human-app/frontend/src/shared/env.ts
new file mode 100644
index 0000000000..6e56a271d9
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/env.ts
@@ -0,0 +1,69 @@
+/* eslint-disable no-console -- .. */
+import { ZodError, z } from 'zod';
+
+const envSchema = z.object({
+ VITE_API_URL: z.string().default('/api'),
+ VITE_PRIVACY_POLICY_URL: z.string(),
+ VITE_TERMS_OF_SERVICE_URL: z.string(),
+ VITE_HUMAN_PROTOCOL_URL: z.string(),
+ VITE_NAVBAR__LINK__PROTOCOL_URL: z.string(),
+ VITE_NAVBAR__LINK__HOW_IT_WORK_URL: z.string(),
+ VITE_HUMAN_PROTOCOL_HELP_URL: z.string(),
+ VITE_WALLET_CONNECT_MODAL_LINK: z.string(),
+ VITE_H_CAPTCHA_SITE_KEY: z.string(),
+ VITE_HMT_DAILY_SPENT_LIMIT: z
+ .string()
+ .transform((value) => Number(value))
+ .pipe(z.number()),
+ VITE_DAILY_SOLVED_CAPTCHA_LIMIT: z
+ .string()
+ .transform((value) => Number(value))
+ .pipe(z.number()),
+ VITE_H_CAPTCHA_EXCHANGE_URL: z.string(),
+ VITE_H_CAPTCHA_LABELING_BASE_URL: z.string(),
+ VITE_WALLET_CONNECT_PROJECT_ID: z.string(),
+ VITE_DAPP_META_NAME: z.string(),
+ VITE_DAPP_META_DESCRIPTION: z.string(),
+ VITE_DAPP_META_URL: z.string(),
+ VITE_DAPP_ICONS: z.string().transform((value) => {
+ const iconsArray = value.split(',');
+ return iconsArray;
+ }),
+ VITE_NETWORK: z.enum(['mainnet', 'testnet']),
+ VITE_TESTNET_AMOY_STAKING_CONTRACT: z.string(),
+ VITE_TESTNET_AMOY_HMTOKEN_CONTRACT: z.string(),
+ VITE_TESTNET_AMOY_ETH_KV_STORE_CONTRACT: z.string(),
+ VITE_MAINNET_POLYGON_STAKING_CONTRACT: z.string(),
+ VITE_MAINNET_POLYGON_HMTOKEN_CONTRACT: z.string(),
+ VITE_MAINNET_POLYGON_ETH_KV_STORE_CONTRACT: z.string(),
+});
+
+let validEnvs;
+
+function setError() {
+ const root = document.getElementById('root');
+ if (!root) return;
+
+ const errorDiv = document.createElement('div');
+ errorDiv.textContent = 'Invalid .env file. Open devtools to see more details';
+ root.appendChild(errorDiv);
+}
+
+try {
+ validEnvs = envSchema.parse(import.meta.env);
+} catch (error) {
+ if (error instanceof ZodError) {
+ console.error('Invalid .env file');
+ error.issues.forEach((issue) => {
+ console.error('Invalid env:', issue.path.join());
+ console.error(issue);
+ });
+ setError();
+ throw new Error();
+ }
+ setError();
+ console.error(error);
+ throw new Error();
+}
+
+export const env = validEnvs;
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/browser-auth-provider.ts b/packages/apps/human-app/frontend/src/shared/helpers/browser-auth-provider.ts
new file mode 100644
index 0000000000..3b3a8b965b
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/browser-auth-provider.ts
@@ -0,0 +1,75 @@
+/* eslint-disable camelcase -- ...*/
+import type { BrowserAuthProvider } from '@/shared/types/browser-auth-provider';
+
+const accessTokenKey = btoa('access_token');
+const refreshTokenKey = btoa('refresh_token');
+const authTypeKey = btoa('auth_type');
+const userDataKey = btoa('extendable_user_data');
+
+const browserAuthProvider: BrowserAuthProvider = {
+ isAuthenticated: false,
+ authType: 'web2',
+ signIn({ access_token, refresh_token }, authType) {
+ browserAuthProvider.isAuthenticated = true;
+ browserAuthProvider.authType = authType;
+ localStorage.setItem(accessTokenKey, btoa(access_token));
+ localStorage.setItem(refreshTokenKey, btoa(refresh_token));
+ localStorage.setItem(authTypeKey, btoa(authType));
+ },
+ signOut(callback) {
+ browserAuthProvider.isAuthenticated = false;
+ localStorage.removeItem(accessTokenKey);
+ localStorage.removeItem(refreshTokenKey);
+ localStorage.removeItem(authTypeKey);
+ localStorage.removeItem(userDataKey);
+ if (callback) {
+ callback();
+ }
+ },
+ getAccessToken() {
+ const result = localStorage.getItem(accessTokenKey);
+ if (!result) {
+ return null;
+ }
+
+ return atob(result);
+ },
+ getRefreshToken() {
+ const result = localStorage.getItem(refreshTokenKey);
+
+ if (!result) {
+ return null;
+ }
+
+ return atob(result);
+ },
+ getAuthType() {
+ const result = localStorage.getItem(authTypeKey);
+
+ if (!result) {
+ return null;
+ }
+
+ return atob(result);
+ },
+ setUserData(userData) {
+ localStorage.setItem(userDataKey, btoa(JSON.stringify(userData)));
+ },
+ getUserData() {
+ const userData = localStorage.getItem(userDataKey);
+
+ if (!userData) {
+ return { data: {} as unknown };
+ }
+
+ try {
+ return {
+ data: JSON.parse(atob(userData)) as unknown,
+ };
+ } catch (error) {
+ return { data: {} as unknown };
+ }
+ },
+};
+
+export { browserAuthProvider };
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/counter-helpers.ts b/packages/apps/human-app/frontend/src/shared/helpers/counter-helpers.ts
new file mode 100644
index 0000000000..a1ced75eff
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/counter-helpers.ts
@@ -0,0 +1,47 @@
+export interface ParsedDate {
+ days: number;
+ hours: number;
+ minutes: number;
+ seconds: number;
+}
+
+export function parseDate(delta: number): ParsedDate {
+ const days = Math.floor(delta / (1000 * 60 * 60 * 24));
+ const hours = Math.floor((delta % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
+ const minutes = Math.floor((delta % (1000 * 60 * 60)) / (1000 * 60));
+ const seconds = Math.floor((delta % (1000 * 60)) / 1000);
+
+ return {
+ days,
+ hours,
+ minutes,
+ seconds,
+ };
+}
+
+export function padZero(num: number): string {
+ return num < 10 ? `0${num}` : `${num}`;
+}
+
+// implementation used like in prev version of human app
+export function getTomorrowDate() {
+ const today = new Date();
+ const timeZoneOffset = today.getTimezoneOffset();
+ const tomorrow = new Date();
+ tomorrow.setDate(today.getDate() + 1);
+ tomorrow.setHours(7);
+ tomorrow.setMinutes(0);
+ tomorrow.setSeconds(0);
+ tomorrow.setMilliseconds(0);
+
+ const DAY_IN_MSS = 24 * 60 * 60 * 1000;
+ const deltaDays = Math.floor(
+ (tomorrow.getTime() - today.getTime()) / DAY_IN_MSS
+ );
+
+ const newDateObj = new Date(
+ tomorrow.getTime() - deltaDays * DAY_IN_MSS - timeZoneOffset * 60000
+ );
+
+ return newDateObj;
+}
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/create-pagination-schema.ts b/packages/apps/human-app/frontend/src/shared/helpers/create-pagination-schema.ts
new file mode 100644
index 0000000000..42693e7ddc
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/create-pagination-schema.ts
@@ -0,0 +1,14 @@
+/* eslint-disable camelcase -- ...*/
+import { z } from 'zod';
+
+export const createPaginationSchema = (
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- keep zod automatic inferring
+ resultsSchema: z.ZodType
+) =>
+ z.object({
+ page: z.number(),
+ page_size: z.number(),
+ total_pages: z.number(),
+ total_results: z.number(),
+ results: z.array(resultsSchema),
+ });
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/create-store-selectors.ts b/packages/apps/human-app/frontend/src/shared/helpers/create-store-selectors.ts
new file mode 100644
index 0000000000..bdcb6a9f3d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/create-store-selectors.ts
@@ -0,0 +1,18 @@
+import type { StoreApi, UseBoundStore } from 'zustand';
+
+type WithSelectors = S extends { getState: () => infer T }
+ ? S & { use: { [K in keyof T]: () => T[K] } }
+ : never;
+
+export const createStoreSelectors = >>(
+ _store: S
+) => {
+ const store = _store as WithSelectors;
+ store.use = {};
+ for (const k of Object.keys(store.getState())) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access -- required
+ (store.use as any)[k] = () => store((s) => s[k as keyof typeof s]);
+ }
+
+ return store;
+};
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/default-error-message.ts b/packages/apps/human-app/frontend/src/shared/helpers/default-error-message.ts
new file mode 100644
index 0000000000..0697af3bd9
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/default-error-message.ts
@@ -0,0 +1,42 @@
+import { t } from 'i18next';
+import { FetchError } from '@/api/fetcher';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+type CustomErrorHandler = (unknownError: unknown) => string | undefined;
+
+export function defaultErrorMessage(
+ unknownError: unknown,
+ customErrorHandler?: CustomErrorHandler
+): string {
+ let customError: string | undefined;
+
+ if (customErrorHandler) {
+ customError = customErrorHandler(unknownError);
+ }
+
+ if (customError) {
+ return customError;
+ }
+
+ if (unknownError instanceof JsonRpcError) {
+ return t('errors.jsonRpcError');
+ }
+
+ if (unknownError instanceof FetchError) {
+ if (typeof unknownError.data === 'string') {
+ return unknownError.data;
+ }
+
+ if (unknownError.message) {
+ return unknownError.message;
+ }
+
+ return t('errors.errorWithStatusCode', { code: unknownError.status });
+ }
+
+ if (unknownError instanceof Error) {
+ return unknownError.message;
+ }
+
+ return t('errors.unknown');
+}
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/format-date.ts b/packages/apps/human-app/frontend/src/shared/helpers/format-date.ts
new file mode 100644
index 0000000000..9825d30afd
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/format-date.ts
@@ -0,0 +1,6 @@
+import { parseISO, format } from 'date-fns';
+
+export const formatDate = (dateString: string) => {
+ const parsedDate = parseISO(dateString);
+ return format(parsedDate, 'yyyy-MM-dd');
+};
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/is-array.ts b/packages/apps/human-app/frontend/src/shared/helpers/is-array.ts
new file mode 100644
index 0000000000..6243123081
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/is-array.ts
@@ -0,0 +1,4 @@
+// eslint-disable-next-line @typescript-eslint/no-explicit-any -- ..
+export function isArray(value: any): value is any[] {
+ return Array.isArray(value);
+}
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/json-rpc-error-handler.ts b/packages/apps/human-app/frontend/src/shared/helpers/json-rpc-error-handler.ts
new file mode 100644
index 0000000000..271091165a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/json-rpc-error-handler.ts
@@ -0,0 +1,9 @@
+import { t } from 'i18next';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export function jsonRpcErrorHandler(unknownError: unknown) {
+ if (unknownError instanceof JsonRpcError) {
+ return unknownError.message;
+ }
+ return t('errors.unknown');
+}
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/regex.ts b/packages/apps/human-app/frontend/src/shared/helpers/regex.ts
new file mode 100644
index 0000000000..957e76e5eb
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/regex.ts
@@ -0,0 +1,11 @@
+export const password8Chars =
+ /^[A-Za-z0-9$^*.[\]{}()?"!@#%&/\\,><':;|_~`=+-]{8,}$/;
+export const passwordUppercase = /(?=.*[A-Z])/;
+export const passwordLowercase = /(?=.*[a-z])/;
+export const passwordNumeric = /(?=.*[0-9])/;
+export const passwordSpecialCharacter =
+ /(?=.*[$^*.[\]{}()?"!@#%&/\\,><':;|_~`=+-])/;
+
+// this is sum of all above regular expressions
+export const passwordRegex =
+ /^(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[$^*.[\]{}()?"!@#%&/\\,><':;|_~`=+-])[A-Za-z0-9$^*.[\]{}()?"!@#%&/\\,><':;|_~`=+-]{8,}$/;
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/shorten-escrow-address.ts b/packages/apps/human-app/frontend/src/shared/helpers/shorten-escrow-address.ts
new file mode 100644
index 0000000000..441bef7cb4
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/shorten-escrow-address.ts
@@ -0,0 +1,6 @@
+export const shortenEscrowAddress = (address: string) => {
+ if (address.length < 13) {
+ return address;
+ }
+ return `${address.substring(0, 7)}...${address.substring(address.length - 5)}`;
+};
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/string-to-upper-snake-case.ts b/packages/apps/human-app/frontend/src/shared/helpers/string-to-upper-snake-case.ts
new file mode 100644
index 0000000000..88a5ded90a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/string-to-upper-snake-case.ts
@@ -0,0 +1,3 @@
+export function stringToUpperSnakeCase(text: string): string {
+ return text.toUpperCase().split(' ').join('_');
+}
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/stringify-url-query-object.ts b/packages/apps/human-app/frontend/src/shared/helpers/stringify-url-query-object.ts
new file mode 100644
index 0000000000..88a8cbc5a2
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/stringify-url-query-object.ts
@@ -0,0 +1,5 @@
+import queryString from 'query-string';
+
+export function stringifyUrlQueryObject(obj: object) {
+ return queryString.stringify(obj);
+}
diff --git a/packages/apps/human-app/frontend/src/shared/helpers/wait.ts b/packages/apps/human-app/frontend/src/shared/helpers/wait.ts
new file mode 100644
index 0000000000..a66480d9c5
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/helpers/wait.ts
@@ -0,0 +1,7 @@
+export const wait = (ms: number): Promise => {
+ return new Promise((resolve) => {
+ setTimeout(() => {
+ resolve(undefined);
+ }, ms);
+ });
+};
diff --git a/packages/apps/human-app/frontend/src/shared/test-utils/render-with-wrapper.tsx b/packages/apps/human-app/frontend/src/shared/test-utils/render-with-wrapper.tsx
new file mode 100644
index 0000000000..18ae3669ee
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/test-utils/render-with-wrapper.tsx
@@ -0,0 +1,16 @@
+import type { RenderOptions } from '@testing-library/react';
+import { render } from '@testing-library/react';
+import { BrowserRouter } from 'react-router-dom';
+import type { ReactElement, ReactNode } from 'react';
+
+//custom wrapper from official documentation https://testing-library.com/docs/react-testing-library/setup/
+export function renderWithWrapper(
+ ui: ReactElement,
+ options?: Omit
+) {
+ function Wrapper({ children }: { children: ReactNode }) {
+ return {children} ;
+ }
+
+ return render(ui, { wrapper: Wrapper, ...options });
+}
diff --git a/packages/apps/human-app/frontend/src/shared/types/browser-auth-provider.ts b/packages/apps/human-app/frontend/src/shared/types/browser-auth-provider.ts
new file mode 100644
index 0000000000..d140d37d04
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/types/browser-auth-provider.ts
@@ -0,0 +1,20 @@
+import type { SignInSuccessResponse } from '@/api/servieces/worker/sign-in';
+import type { Web3UserData } from '@/auth-web3/web3-auth-context';
+import type { UserData } from '@/auth/auth-context';
+
+export type AuthType = 'web2' | 'web3';
+
+export interface BrowserAuthProvider {
+ isAuthenticated: boolean;
+ authType: AuthType;
+ signIn: (
+ singInSuccessData: SignInSuccessResponse,
+ authType: AuthType
+ ) => void;
+ signOut: (callback?: () => void) => void;
+ getAccessToken: () => string | null;
+ getRefreshToken: () => string | null;
+ getAuthType: () => string | null;
+ setUserData: (userData: UserData | Web3UserData) => void;
+ getUserData: () => { data: unknown };
+}
diff --git a/packages/apps/human-app/frontend/src/shared/types/entity.type.ts b/packages/apps/human-app/frontend/src/shared/types/entity.type.ts
new file mode 100644
index 0000000000..892e45b12d
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/types/entity.type.ts
@@ -0,0 +1,5 @@
+import { z } from 'zod';
+
+export const testDataSchema = z.coerce.date();
+export type TestData = z.infer;
+export type PageSize = 5 | 10;
diff --git a/packages/apps/human-app/frontend/src/shared/types/global.type.ts b/packages/apps/human-app/frontend/src/shared/types/global.type.ts
new file mode 100644
index 0000000000..9c54b4adee
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/types/global.type.ts
@@ -0,0 +1,17 @@
+import type { ZodError } from 'zod';
+import type { FetchError } from '@/api/fetcher';
+import type { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export interface Children {
+ children?: React.ReactNode;
+}
+
+export type ResponseError = FetchError | Error | ZodError | JsonRpcError | null;
+
+declare module '@tanstack/react-query' {
+ interface Register {
+ defaultError: ResponseError;
+ }
+}
+
+export type FormNotifications = 'warning' | 'error' | 'default';
diff --git a/packages/apps/human-app/frontend/src/shared/types/svg.d.ts b/packages/apps/human-app/frontend/src/shared/types/svg.d.ts
new file mode 100644
index 0000000000..7a9b19df95
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/shared/types/svg.d.ts
@@ -0,0 +1,11 @@
+declare module '*.svg' {
+ const ReactComponent: React.FC>;
+ // eslint-disable-next-line import/no-default-export -- export vite config
+ export default ReactComponent;
+}
+
+declare module '*.svg?url' {
+ const content: string;
+ // eslint-disable-next-line import/no-default-export -- export vite config
+ export default content;
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/config.ts b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/config.ts
new file mode 100644
index 0000000000..e268e3b2e8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/config.ts
@@ -0,0 +1,40 @@
+export enum Role {
+ JobLauncher = 'Job launcher',
+ ExchangeOracle = 'Exchange Oracle',
+ ReputationOracle = 'Reputation Oracle',
+ RecordingOracle = 'Recording Oracle',
+}
+
+export enum JobTypes {
+ Fortune = 'Fortune',
+ Points = 'Points',
+ BoundingBoxes = 'Bounding Boxes',
+ BoundingBoxesFromPoints = 'Bounding Boxes from points',
+ SkeletonsFromBoundingBoxes = 'Skeletons from Bounding Boxes',
+}
+
+export const EthKVStoreKeys = {
+ PublicKey: 'public_key',
+ Url: 'url',
+ WebhookUrl: 'webhook_url',
+ Role: 'role',
+ Fee: 'fee',
+ JobTypes: 'job_types',
+} as const;
+
+export type EthKVStoreKeyValues =
+ (typeof EthKVStoreKeys)[keyof typeof EthKVStoreKeys];
+
+export type SetBulkKeys = string[];
+
+export type SetBulkValues = string[];
+export interface SetOperatorPayload {
+ keys: SetBulkKeys;
+ values: SetBulkValues;
+}
+
+export type KYCKey = `KYC-${string}`;
+export interface SetKYCPayload {
+ keys: [KYCKey];
+ values: [string];
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-get-keys.ts b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-get-keys.ts
new file mode 100644
index 0000000000..f0a35affc2
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-get-keys.ts
@@ -0,0 +1,38 @@
+import { Contract } from 'ethers';
+import EthKVStore from '@/smart-contracts/abi/EthKVStore.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import { EthKVStoreKeys } from '@/smart-contracts/EthKVStore/config';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export async function ethKVStoreGetKeys({
+ accountAddress,
+ contractAddress,
+ signer,
+}: { accountAddress: string } & ContractCallArguments) {
+ try {
+ const ethKVStoreContract = new Contract(
+ contractAddress,
+ EthKVStore.abi,
+ signer
+ );
+ const keys = (await Promise.all([
+ ethKVStoreContract.get(accountAddress, EthKVStoreKeys.PublicKey),
+ ethKVStoreContract.get(accountAddress, EthKVStoreKeys.Url),
+ ethKVStoreContract.get(accountAddress, EthKVStoreKeys.WebhookUrl),
+ ethKVStoreContract.get(accountAddress, EthKVStoreKeys.Role),
+ ethKVStoreContract.get(accountAddress, EthKVStoreKeys.JobTypes),
+ ethKVStoreContract.get(accountAddress, EthKVStoreKeys.Fee),
+ ])) as unknown as string[];
+
+ return {
+ [EthKVStoreKeys.PublicKey]: keys[0],
+ [EthKVStoreKeys.Url]: keys[1],
+ [EthKVStoreKeys.WebhookUrl]: keys[2],
+ [EthKVStoreKeys.Role]: keys[3],
+ [EthKVStoreKeys.JobTypes]: keys[4],
+ [EthKVStoreKeys.Fee]: keys[5],
+ };
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-get-kyc-data.ts b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-get-kyc-data.ts
new file mode 100644
index 0000000000..35a9da78cc
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-get-kyc-data.ts
@@ -0,0 +1,43 @@
+import { Contract, ethers } from 'ethers';
+import EthKVStore from '@/smart-contracts/abi/EthKVStore.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import type { KYCKey } from '@/smart-contracts/EthKVStore/config';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+import { env } from '@/shared/env';
+import type { ChainWithAddresses } from '@/smart-contracts/chains';
+import { MainnetChains, TestnetChains } from '@/smart-contracts/chains';
+
+export async function ethKVStoreGetKycData({
+ kycKey,
+ accountAddress,
+ contractAddress,
+}: { kycKey: KYCKey; accountAddress: string } & Omit<
+ ContractCallArguments,
+ 'chainId' | 'signer'
+>) {
+ try {
+ let chain: ChainWithAddresses | undefined;
+
+ if (env.VITE_NETWORK === 'mainnet') {
+ chain = MainnetChains[0];
+ } else {
+ chain = TestnetChains[0];
+ }
+
+ const provider = new ethers.JsonRpcProvider(chain.rpcUrl);
+
+ const ethKVStoreContract = new Contract(
+ contractAddress,
+ EthKVStore.abi,
+ provider
+ );
+
+ const result = (await ethKVStoreContract.get(accountAddress, kycKey)) as
+ | string
+ | null;
+
+ return result;
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-set-bulk.ts b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-set-bulk.ts
new file mode 100644
index 0000000000..13442ada46
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/EthKVStore/eth-kv-store-set-bulk.ts
@@ -0,0 +1,30 @@
+import { Contract } from 'ethers';
+import EthKVStore from '@/smart-contracts/abi/EthKVStore.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import type {
+ SetKYCPayload,
+ SetOperatorPayload,
+} from '@/smart-contracts/EthKVStore/config';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export async function ethKvStoreSetBulk({
+ keys,
+ values,
+ contractAddress,
+ signer,
+}: (SetOperatorPayload | SetKYCPayload) & ContractCallArguments) {
+ try {
+ const ethKVStoreContract = new Contract(
+ contractAddress,
+ EthKVStore.abi,
+ signer
+ );
+
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- untyped ethers
+ const tx = await ethKVStoreContract.setBulk(keys, values);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access -- untyped ethers
+ await tx.wait();
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-allowance.ts b/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-allowance.ts
new file mode 100644
index 0000000000..d318b5f9a8
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-allowance.ts
@@ -0,0 +1,23 @@
+import { Contract } from 'ethers';
+import HMToken from '@/smart-contracts/abi/HMToken.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export async function hmTokenAllowance({
+ spender,
+ owner,
+ contractAddress,
+ signer,
+}: { spender: string; owner: string } & ContractCallArguments) {
+ try {
+ const hmTokenContract = new Contract(contractAddress, HMToken.abi, signer);
+ const allowanceResult = (await hmTokenContract.getFunction('allowance')(
+ owner,
+ spender
+ )) as Promise;
+
+ return allowanceResult;
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-approve.ts b/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-approve.ts
new file mode 100644
index 0000000000..ad3156d484
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-approve.ts
@@ -0,0 +1,24 @@
+import { Contract } from 'ethers';
+import HMToken from '@/smart-contracts/abi/HMToken.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export async function hmTokenApprove({
+ contractAddress,
+ spender,
+ amount,
+ signer,
+}: {
+ spender: string;
+ amount: string;
+} & ContractCallArguments) {
+ try {
+ const hmTokenContract = new Contract(contractAddress, HMToken.abi, signer);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- untyped ethers
+ const tx = await hmTokenContract.approve(spender, amount);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access -- untyped ethers
+ await tx.wait();
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-decimals.ts b/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-decimals.ts
new file mode 100644
index 0000000000..a9c10bf0fa
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/HMToken/hm-token-decimals.ts
@@ -0,0 +1,20 @@
+import { Contract } from 'ethers';
+import HMToken from '@/smart-contracts/abi/HMToken.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export async function hmTokenDecimals({
+ contractAddress,
+ signer,
+}: ContractCallArguments) {
+ try {
+ const hmTokenContract = new Contract(contractAddress, HMToken.abi, signer);
+ const decimalsResult = (await hmTokenContract.getFunction(
+ 'decimals'
+ )()) as Promise;
+
+ return Number(decimalsResult);
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/Staking/staking-get-staked-tokens.ts b/packages/apps/human-app/frontend/src/smart-contracts/Staking/staking-get-staked-tokens.ts
new file mode 100644
index 0000000000..427c6ca8a3
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/Staking/staking-get-staked-tokens.ts
@@ -0,0 +1,21 @@
+import { Contract } from 'ethers';
+import Staking from '@/smart-contracts/abi/Staking.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export async function stakingGetStakedTokens({
+ contractAddress,
+ stakerAddress,
+ signer,
+}: {
+ stakerAddress: string;
+} & ContractCallArguments) {
+ try {
+ const stakingContract = new Contract(contractAddress, Staking.abi, signer);
+ return (await stakingContract.getFunction('getStakedTokens')(
+ stakerAddress
+ )) as Promise;
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/Staking/staking-stake.ts b/packages/apps/human-app/frontend/src/smart-contracts/Staking/staking-stake.ts
new file mode 100644
index 0000000000..bad8b02ead
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/Staking/staking-stake.ts
@@ -0,0 +1,23 @@
+import { Contract } from 'ethers';
+import Staking from '@/smart-contracts/abi/Staking.json';
+import type { ContractCallArguments } from '@/smart-contracts/types';
+import { JsonRpcError } from '@/smart-contracts/json-rpc-error';
+
+export async function stakingStake({
+ contractAddress,
+ amount,
+ signer,
+}: {
+ address: string;
+ amount: string;
+} & ContractCallArguments) {
+ try {
+ const stakingContract = new Contract(contractAddress, Staking.abi, signer);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- untyped ethers
+ const tx = await stakingContract.stake(amount);
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access -- untyped ethers
+ await tx.wait();
+ } catch (error) {
+ throw new JsonRpcError(error);
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/abi/EthKVStore.json b/packages/apps/human-app/frontend/src/smart-contracts/abi/EthKVStore.json
new file mode 100644
index 0000000000..e0caef960f
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/abi/EthKVStore.json
@@ -0,0 +1,89 @@
+{
+ "abi": [
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "internalType": "address",
+ "name": "sender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "key",
+ "type": "string"
+ },
+ {
+ "indexed": false,
+ "internalType": "string",
+ "name": "value",
+ "type": "string"
+ }
+ ],
+ "name": "DataSaved",
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "address",
+ "name": "_account",
+ "type": "address"
+ },
+ {
+ "internalType": "string",
+ "name": "_key",
+ "type": "string"
+ }
+ ],
+ "name": "get",
+ "outputs": [
+ {
+ "internalType": "string",
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string",
+ "name": "_key",
+ "type": "string"
+ },
+ {
+ "internalType": "string",
+ "name": "_value",
+ "type": "string"
+ }
+ ],
+ "name": "set",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "inputs": [
+ {
+ "internalType": "string[]",
+ "name": "_keys",
+ "type": "string[]"
+ },
+ {
+ "internalType": "string[]",
+ "name": "_values",
+ "type": "string[]"
+ }
+ ],
+ "name": "setBulk",
+ "outputs": [],
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+ ]
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/abi/HMToken.json b/packages/apps/human-app/frontend/src/smart-contracts/abi/HMToken.json
new file mode 100644
index 0000000000..e6ae0dd8e3
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/abi/HMToken.json
@@ -0,0 +1,224 @@
+{
+ "abi": [
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_spender",
+ "type": "address"
+ },
+ {
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_from",
+ "type": "address"
+ },
+ {
+ "name": "_to",
+ "type": "address"
+ },
+ {
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "name": "balance",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [
+ {
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_to",
+ "type": "address"
+ },
+ {
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_owner",
+ "type": "address"
+ },
+ {
+ "name": "_spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "payable": true,
+ "stateMutability": "payable",
+ "type": "fallback"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ }
+ ]
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/abi/Staking.json b/packages/apps/human-app/frontend/src/smart-contracts/abi/Staking.json
new file mode 100644
index 0000000000..fa3d4851f9
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/abi/Staking.json
@@ -0,0 +1,694 @@
+{
+ "abi": [
+ { "inputs": [], "stateMutability": "nonpayable", "type": "constructor" },
+ {
+ "inputs": [
+ {
+ "indexed": false,
+ "name": "previousAdmin",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "newAdmin",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "AdminChanged",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "staker",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "tokens",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "name": "escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "closedAt",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "AllocationClosed",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "beacon",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "BeaconUpgraded",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": false,
+ "name": "version",
+ "internalType": "uint8",
+ "type": "uint8"
+ }
+ ],
+ "name": "Initialized",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "previousOwner",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "newOwner",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "OwnershipTransferred",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "lockPeriod",
+ "internalType": "uint32",
+ "type": "uint32"
+ }
+ ],
+ "name": "SetLockPeriod",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "minimumStake",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "SetMinumumStake",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "rewardPool",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "SetRewardPool",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "staker",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "tokens",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "name": "escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "createdAt",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "StakeAllocated",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "staker",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "tokens",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "StakeDeposited",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "staker",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "tokens",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "indexed": false,
+ "name": "until",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "StakeLocked",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "staker",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "tokens",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "indexed": true,
+ "name": "escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "slasher",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "StakeSlashed",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "staker",
+ "internalType": "address",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "tokens",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "StakeWithdrawn",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "implementation",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "Upgraded",
+ "anonymous": false,
+ "type": "event"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ {
+ "name": "_escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ },
+ { "name": "_tokens", "internalType": "uint256", "type": "uint256" }
+ ],
+ "name": "allocate",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [
+ {
+ "name": "escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ },
+ { "name": "staker", "internalType": "address", "type": "address" },
+ { "name": "tokens", "internalType": "uint256", "type": "uint256" },
+ { "name": "createdAt", "internalType": "uint256", "type": "uint256" },
+ { "name": "closedAt", "internalType": "uint256", "type": "uint256" }
+ ],
+ "inputs": [{ "name": "", "internalType": "address", "type": "address" }],
+ "name": "allocations",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ {
+ "name": "_escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "closeAllocation",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [
+ {
+ "components": [
+ {
+ "name": "escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ },
+ { "name": "staker", "internalType": "address", "type": "address" },
+ { "name": "tokens", "internalType": "uint256", "type": "uint256" },
+ {
+ "name": "createdAt",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ { "name": "closedAt", "internalType": "uint256", "type": "uint256" }
+ ],
+ "name": "",
+ "internalType": "struct IStaking.Allocation",
+ "type": "tuple"
+ }
+ ],
+ "inputs": [
+ {
+ "name": "_escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "getAllocation",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [
+ {
+ "name": "",
+ "internalType": "enum IStaking.AllocationState",
+ "type": "uint8"
+ }
+ ],
+ "inputs": [
+ {
+ "name": "_escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "getAllocationState",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [
+ { "name": "", "internalType": "address[]", "type": "address[]" },
+ {
+ "components": [
+ {
+ "name": "tokensStaked",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensAllocated",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensLocked",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensLockedUntil",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "",
+ "internalType": "struct Stakes.Staker[]",
+ "type": "tuple[]"
+ }
+ ],
+ "inputs": [],
+ "name": "getListOfStakers",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "uint256", "type": "uint256" }],
+ "inputs": [
+ { "name": "_staker", "internalType": "address", "type": "address" }
+ ],
+ "name": "getStakedTokens",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [
+ {
+ "components": [
+ {
+ "name": "tokensStaked",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensAllocated",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensLocked",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensLockedUntil",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "",
+ "internalType": "struct Stakes.Staker",
+ "type": "tuple"
+ }
+ ],
+ "inputs": [
+ { "name": "_staker", "internalType": "address", "type": "address" }
+ ],
+ "name": "getStaker",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "bool", "type": "bool" }],
+ "inputs": [
+ { "name": "_staker", "internalType": "address", "type": "address" }
+ ],
+ "name": "hasAvailableStake",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "bool", "type": "bool" }],
+ "inputs": [
+ { "name": "_staker", "internalType": "address", "type": "address" }
+ ],
+ "name": "hasStake",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ { "name": "_token", "internalType": "address", "type": "address" },
+ {
+ "name": "_minimumStake",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ { "name": "_lockPeriod", "internalType": "uint32", "type": "uint32" }
+ ],
+ "name": "initialize",
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "bool", "type": "bool" }],
+ "inputs": [
+ {
+ "name": "_escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "isAllocation",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "uint32", "type": "uint32" }],
+ "inputs": [],
+ "name": "lockPeriod",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "uint256", "type": "uint256" }],
+ "inputs": [],
+ "name": "minimumStake",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "address", "type": "address" }],
+ "inputs": [],
+ "name": "owner",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "bytes32", "type": "bytes32" }],
+ "inputs": [],
+ "name": "proxiableUUID",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [],
+ "name": "renounceOwnership",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "address", "type": "address" }],
+ "inputs": [],
+ "name": "rewardPool",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ { "name": "_lockPeriod", "internalType": "uint32", "type": "uint32" }
+ ],
+ "name": "setLockPeriod",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ {
+ "name": "_minimumStake",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "name": "setMinimumStake",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ { "name": "_rewardPool", "internalType": "address", "type": "address" }
+ ],
+ "name": "setRewardPool",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ { "name": "_slasher", "internalType": "address", "type": "address" },
+ { "name": "_staker", "internalType": "address", "type": "address" },
+ {
+ "name": "_escrowAddress",
+ "internalType": "address",
+ "type": "address"
+ },
+ { "name": "_tokens", "internalType": "uint256", "type": "uint256" }
+ ],
+ "name": "slash",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ { "name": "_tokens", "internalType": "uint256", "type": "uint256" }
+ ],
+ "name": "stake",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "address", "type": "address" }],
+ "inputs": [{ "name": "", "internalType": "uint256", "type": "uint256" }],
+ "name": "stakers",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [
+ {
+ "name": "tokensStaked",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensAllocated",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensLocked",
+ "internalType": "uint256",
+ "type": "uint256"
+ },
+ {
+ "name": "tokensLockedUntil",
+ "internalType": "uint256",
+ "type": "uint256"
+ }
+ ],
+ "inputs": [{ "name": "", "internalType": "address", "type": "address" }],
+ "name": "stakes",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [{ "name": "", "internalType": "address", "type": "address" }],
+ "inputs": [],
+ "name": "token",
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ { "name": "newOwner", "internalType": "address", "type": "address" }
+ ],
+ "name": "transferOwnership",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ { "name": "_tokens", "internalType": "uint256", "type": "uint256" }
+ ],
+ "name": "unstake",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ {
+ "name": "newImplementation",
+ "internalType": "address",
+ "type": "address"
+ }
+ ],
+ "name": "upgradeTo",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [
+ {
+ "name": "newImplementation",
+ "internalType": "address",
+ "type": "address"
+ },
+ { "name": "data", "internalType": "bytes", "type": "bytes" }
+ ],
+ "name": "upgradeToAndCall",
+ "stateMutability": "payable",
+ "type": "function"
+ },
+ {
+ "outputs": [],
+ "inputs": [],
+ "name": "withdraw",
+ "stateMutability": "nonpayable",
+ "type": "function"
+ }
+ ]
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/chains.ts b/packages/apps/human-app/frontend/src/smart-contracts/chains.ts
new file mode 100644
index 0000000000..edb3801812
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/chains.ts
@@ -0,0 +1,49 @@
+// This file defines chains that will be available in wallet-connect modal
+// according to docs: https://docs.walletconnect.com/web3modal/react/about.
+// For particular chains we define set of smart contract addresses.
+// Thanks to that we can get addresses for selected chain with getContractAddress
+// function
+
+import type { Chain } from '@web3modal/scaffold-utils/ethers';
+import {
+ MainnetContracts,
+ TestnetContracts,
+ type ContractsAddresses,
+} from '@/smart-contracts/contracts';
+
+export type ChainWithAddresses = Chain & {
+ addresses: ContractsAddresses;
+};
+
+export const TestnetChains: ChainWithAddresses[] = [
+ {
+ chainId: 80002,
+ name: 'Amoy',
+ rpcUrl: 'https://rpc-amoy.polygon.technology',
+ currency: 'MATIC',
+ explorerUrl: 'https://www.oklink.com/amoy',
+ addresses: TestnetContracts.Amoy,
+ },
+];
+
+export const MainnetChains: ChainWithAddresses[] = [
+ {
+ chainId: 137,
+ name: 'Polygon',
+ rpcUrl: 'https://polygon-rpc.com/',
+ currency: 'MATIC',
+ explorerUrl: 'https://polygonscan.com/',
+ addresses: MainnetContracts.Polygon,
+ },
+];
+
+// chains for getContractAddress function
+export const chainsWithSCAddresses: ChainWithAddresses[] = [
+ ...TestnetChains,
+ ...MainnetChains,
+];
+
+// chains for wallet-connect modal
+export const chains: Chain[] = [...TestnetChains, ...MainnetChains].map(
+ ({ addresses: _, ...chainData }) => chainData
+);
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/check-network.ts b/packages/apps/human-app/frontend/src/smart-contracts/check-network.ts
new file mode 100644
index 0000000000..5f128225cc
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/check-network.ts
@@ -0,0 +1,18 @@
+import { t } from 'i18next';
+import type { Network } from 'ethers';
+import { MainnetChains, TestnetChains } from '@/smart-contracts/chains';
+import { env } from '@/shared/env';
+
+export const checkNetwork = (network: Network): void => {
+ if (env.VITE_NETWORK === 'testnet') {
+ if (BigInt(TestnetChains[0].chainId) === network.chainId) return;
+ throw new Error(
+ t('errors.unsupportedNetworkWithName', { networkName: network.name })
+ );
+ } else {
+ if (BigInt(MainnetChains[0].chainId) === network.chainId) return;
+ throw new Error(
+ t('errors.unsupportedNetworkWithName', { networkName: network.name })
+ );
+ }
+};
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/contracts.ts b/packages/apps/human-app/frontend/src/smart-contracts/contracts.ts
new file mode 100644
index 0000000000..b818a7f274
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/contracts.ts
@@ -0,0 +1,29 @@
+// this file defines contract addresses
+// from https://docs.humanprotocol.org/human-tech-docs/architecture/components/smart-contracts/contract-addresses
+
+import { env } from '@/shared/env';
+
+export interface ContractsAddresses {
+ HMToken: string;
+ Staking: string;
+ EthKVStore: string;
+}
+
+export type Testnet = 'Amoy';
+export type Mainnet = 'Polygon';
+
+export const TestnetContracts: Record = {
+ Amoy: {
+ Staking: env.VITE_TESTNET_AMOY_STAKING_CONTRACT,
+ HMToken: env.VITE_TESTNET_AMOY_HMTOKEN_CONTRACT,
+ EthKVStore: env.VITE_TESTNET_AMOY_ETH_KV_STORE_CONTRACT,
+ },
+};
+
+export const MainnetContracts: Record = {
+ Polygon: {
+ Staking: env.VITE_MAINNET_POLYGON_STAKING_CONTRACT,
+ HMToken: env.VITE_MAINNET_POLYGON_HMTOKEN_CONTRACT,
+ EthKVStore: env.VITE_MAINNET_POLYGON_ETH_KV_STORE_CONTRACT,
+ },
+};
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/get-contract-address.ts b/packages/apps/human-app/frontend/src/smart-contracts/get-contract-address.ts
new file mode 100644
index 0000000000..00fe717331
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/get-contract-address.ts
@@ -0,0 +1,14 @@
+import { MainnetChains, TestnetChains } from '@/smart-contracts/chains';
+import type { ContractsAddresses } from '@/smart-contracts/contracts';
+import { env } from '@/shared/env';
+
+export const getContractAddress = ({
+ contractName,
+}: {
+ contractName: keyof ContractsAddresses;
+}): string => {
+ if (env.VITE_NETWORK === 'testnet') {
+ return TestnetChains[0].addresses[contractName];
+ }
+ return MainnetChains[0].addresses[contractName];
+};
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/get-network-name.ts b/packages/apps/human-app/frontend/src/smart-contracts/get-network-name.ts
new file mode 100644
index 0000000000..22717f2b5a
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/get-network-name.ts
@@ -0,0 +1,9 @@
+import { MainnetChains, TestnetChains } from '@/smart-contracts/chains';
+import { env } from '@/shared/env';
+
+export const getNetworkName = (): string => {
+ if (env.VITE_NETWORK === 'testnet') {
+ return TestnetChains[0]?.name;
+ }
+ return MainnetChains[0]?.name;
+};
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/json-rpc-error.ts b/packages/apps/human-app/frontend/src/smart-contracts/json-rpc-error.ts
new file mode 100644
index 0000000000..aa051b5d26
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/json-rpc-error.ts
@@ -0,0 +1,13 @@
+import { t } from 'i18next';
+
+export class JsonRpcError extends Error {
+ metadata: unknown;
+ constructor(metadata: unknown) {
+ // eslint-disable-next-line no-console -- ...
+ console.error(metadata);
+ super(t('errors.jsonRpcError'));
+ this.name = this.constructor.name;
+ Object.setPrototypeOf(this, new.target.prototype);
+ this.metadata = metadata;
+ }
+}
diff --git a/packages/apps/human-app/frontend/src/smart-contracts/types.ts b/packages/apps/human-app/frontend/src/smart-contracts/types.ts
new file mode 100644
index 0000000000..de7e0dbe96
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/smart-contracts/types.ts
@@ -0,0 +1,8 @@
+import type { BrowserProvider, JsonRpcSigner } from 'ethers';
+
+export interface ContractCallArguments {
+ contractAddress: string;
+ chainId: number;
+ provider?: BrowserProvider;
+ signer?: JsonRpcSigner;
+}
diff --git a/packages/apps/human-app/frontend/src/styles/color-palette.ts b/packages/apps/human-app/frontend/src/styles/color-palette.ts
new file mode 100644
index 0000000000..8ab59e2068
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/styles/color-palette.ts
@@ -0,0 +1,48 @@
+export const colorPalette = {
+ white: '#FFFFFF',
+ black: '#000000',
+ text: {
+ primary: '#320A8D',
+ secondary: '#858EC6',
+ disabled: '#CBCFE6',
+ disabledSecondary: '#8494C3',
+ },
+ primary: {
+ main: '#320A8D',
+ light: '#6309FF',
+ dark: '#100735',
+ contrastText: '#F9FAFF',
+ },
+ secondary: {
+ main: '#6309FF',
+ dark: '#4506B2',
+ light: '#8409FF',
+ contrastText: '#FFFFFF',
+ },
+ error: {
+ main: '#FA2A75',
+ dark: '#F20D5F',
+ light: '#FF5995',
+ contrastText: '#FFFFFF',
+ },
+ success: {
+ main: '#0AD397',
+ dark: '#0E976E',
+ light: '#00EDA6',
+ contrastText: '#FFFFFF',
+ },
+ paper: {
+ main: '#F6F7FE',
+ light: '#F6F6FF',
+ text: '#CBCFE8',
+ disabled: '#FBFBFE',
+ },
+ chip: {
+ main: 'rgba(203, 207, 232, 0.28)',
+ },
+ button: {
+ disabled: 'rgba(218, 222, 240, 0.8)',
+ },
+ // for 'warning', 'info' native colors from MUI were pointed as expected
+ // 'info' native colors from MUI were pointed as expected
+} as const;
diff --git a/packages/apps/human-app/frontend/src/styles/theme.ts b/packages/apps/human-app/frontend/src/styles/theme.ts
new file mode 100644
index 0000000000..cfe12d27bf
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/styles/theme.ts
@@ -0,0 +1,398 @@
+import type { CSSProperties } from 'react';
+import type { ThemeOptions } from '@mui/material';
+import { colorPalette } from '@/styles/color-palette';
+
+declare module '@mui/material/Typography' {
+ interface TypographyPropsVariantOverrides {
+ textField: true;
+ body3: true;
+ body4: true;
+ body5: true;
+ body6: true;
+ body7: true;
+ body8: true;
+ buttonLarge: true;
+ buttonMedium: true;
+ buttonSmall: true;
+ inputLabel: true;
+ helperText: true;
+ avatarLetter: true;
+ inputText: true;
+ tooltip: true;
+ inputUnderline: true;
+ chip: true;
+ mobileHeaderLarge: true;
+ mobileHeaderMid: true;
+ }
+}
+
+declare module '@mui/material/styles' {
+ interface TypographyVariants {
+ textField: CSSProperties;
+ body3: CSSProperties;
+ body4: CSSProperties;
+ body5: CSSProperties;
+ body6: CSSProperties;
+ body7: CSSProperties;
+ body8: CSSProperties;
+ buttonLarge: CSSProperties;
+ buttonMedium: CSSProperties;
+ buttonSmall: CSSProperties;
+ inputLabel: CSSProperties;
+ helperText: CSSProperties;
+ avatarLetter: CSSProperties;
+ inputText: CSSProperties;
+ tooltip: CSSProperties;
+ inputUnderline: CSSProperties;
+ chip: CSSProperties;
+ mobileHeaderLarge: CSSProperties;
+ mobileHeaderMid: CSSProperties;
+ }
+
+ // allow configuration using `createTheme`
+ interface TypographyVariantsOptions {
+ textField?: CSSProperties;
+ body3?: CSSProperties;
+ body4?: CSSProperties;
+ body5?: CSSProperties;
+ body6?: CSSProperties;
+ body7?: CSSProperties;
+ body8?: CSSProperties;
+ buttonLarge?: CSSProperties;
+ buttonMedium?: CSSProperties;
+ buttonSmall?: CSSProperties;
+ inputLabel?: CSSProperties;
+ helperText?: CSSProperties;
+ avatarLetter?: CSSProperties;
+ inputText?: CSSProperties;
+ tooltip?: CSSProperties;
+ inputUnderline?: CSSProperties;
+ chip?: CSSProperties;
+ mobileHeaderLarge?: CSSProperties;
+ mobileHeaderMid?: CSSProperties;
+ }
+}
+
+export const breakpoints = {
+ mobile: '@media (max-width:900px)',
+ tablet: '@media (max-width:1200px)',
+};
+
+export const theme: ThemeOptions = {
+ typography: {
+ h1: {
+ fontSize: 80,
+ fontWeight: 800,
+ letterSpacing: -0.5,
+ [breakpoints.mobile]: {
+ fontSize: 40,
+ },
+ },
+ h2: {
+ fontSize: 60,
+ fontWeight: 600,
+ letterSpacing: -0.5,
+ [breakpoints.mobile]: {
+ fontSize: 36,
+ },
+ },
+ h3: {
+ fontSize: 48,
+ fontWeight: 400,
+ letterSpacing: 0,
+ [breakpoints.mobile]: {
+ fontSize: 20,
+ fontWeight: 500,
+ letterSpacing: 0.15,
+ },
+ },
+ h4: {
+ fontSize: 34,
+ fontWeight: 600,
+ letterSpacing: 0.25,
+ [breakpoints.mobile]: {
+ fontSize: 28,
+ fontWeight: 600,
+ letterSpacing: 0.15,
+ },
+ },
+ mobileHeaderLarge: {
+ fontSize: 26,
+ fontWeight: 500,
+ letterSpacing: 0.15,
+ },
+ h5: {
+ fontSize: 24,
+ fontWeight: 400,
+ letterSpacing: 0,
+ [breakpoints.mobile]: {
+ fontSize: 24,
+ },
+ },
+ mobileHeaderMid: {
+ fontSize: 22,
+ fontWeight: 500,
+ letterSpacing: 0.58,
+ },
+ h6: {
+ fontSize: 20,
+ fontWeight: 500,
+ letterSpacing: 0.15,
+ [breakpoints.mobile]: {
+ fontSize: 20,
+ },
+ },
+ subtitle1: {
+ fontSize: 16,
+ fontWeight: 400,
+ letterSpacing: 0.15,
+ [breakpoints.mobile]: {
+ fontSize: 16,
+ },
+ },
+ subtitle2: {
+ fontSize: 14,
+ fontWeight: 600,
+ letterSpacing: 0.1,
+ [breakpoints.mobile]: {
+ fontSize: 14,
+ },
+ },
+ body1: {
+ fontSize: 16,
+ fontWeight: 400,
+ letterSpacing: 0.15,
+ [breakpoints.mobile]: {
+ fontSize: 16,
+ },
+ },
+ body2: {
+ fontSize: 14,
+ fontWeight: 400,
+ letterSpacing: 0.15,
+ [breakpoints.mobile]: {
+ fontSize: 14,
+ },
+ },
+ body3: {
+ fontSize: 16,
+ fontWeight: 500,
+ letterSpacing: 0.15,
+ },
+ body4: {
+ fontSize: 24,
+ fontWeight: 600,
+ letterSpacing: 0.15,
+ },
+ body5: {
+ fontSize: 20,
+ fontWeight: 500,
+ letterSpacing: 0.15,
+ },
+ body6: {
+ fontSize: 24,
+ fontWeight: 600,
+ letterSpacing: 0.15,
+ },
+ body7: {
+ fontSize: 18,
+ fontWeight: 500,
+ letterSpacing: 0.15,
+ },
+ body8: {
+ fontSize: 10,
+ fontWeight: 400,
+ fontStyle: 'italic',
+ lineHeight: '0.1rem',
+ letterSpacing: 0.15,
+ },
+ buttonLarge: {
+ fontSize: 15,
+ fontWeight: 600,
+ letterSpacing: 0.1,
+ },
+ buttonMedium: {
+ fontSize: 14,
+ fontWeight: 600,
+ letterSpacing: 0.1,
+ },
+ buttonSmall: {
+ fontSize: 13,
+ fontWeight: 600,
+ letterSpacing: 0.1,
+ },
+ caption: {
+ fontSize: 12,
+ fontWeight: 400,
+ letterSpacing: 0.4,
+ },
+ overline: {
+ fontSize: 12,
+ fontWeight: 400,
+ letterSpacing: 0.4,
+ textTransform: 'uppercase',
+ },
+ avatarLetter: {
+ fontSize: 20,
+ fontWeight: 400,
+ letterSpacing: 0.14,
+ },
+ inputLabel: {
+ fontSize: 12,
+ fontWeight: 400,
+ letterSpacing: 0.15,
+ },
+ helperText: {
+ fontSize: 12,
+ fontWeight: 400,
+ letterSpacing: 0.4,
+ },
+ inputText: {
+ fontSize: 16,
+ fontWeight: 400,
+ letterSpacing: 0.15,
+ },
+ tooltip: {
+ fontSize: 10,
+ fontWeight: 500,
+ letterSpacing: 0,
+ },
+ inputUnderline: {
+ fontSize: 12,
+ fontWeight: 600,
+ letterSpacing: 0.15,
+ textDecoration: 'underline',
+ },
+ chip: {
+ fontSize: 13,
+ fontWeight: 400,
+ letterSpacing: 0.16,
+ },
+ },
+ components: {
+ MuiTypography: {
+ defaultProps: {
+ variant: 'body1',
+ color: colorPalette.primary.main,
+ fontFamily: 'Inter',
+ variantMapping: {
+ subtitle1: 'p',
+ subtitle2: 'p',
+ textField: 'p',
+ },
+ },
+ },
+ MuiButton: {
+ styleOverrides: {
+ root: {
+ paddingTop: '0.6rem',
+ paddingBottom: '0.6rem',
+ fontSize: '14px',
+ fontWeight: 600,
+ textTransform: 'none',
+ '&.Mui-disabled': {
+ backgroundColor: colorPalette.button.disabled,
+ color: colorPalette.text.secondary,
+ },
+ },
+ },
+ },
+ MuiCheckbox: {
+ styleOverrides: {
+ root: {
+ '&.Mui-checked': {
+ color: colorPalette.primary.main,
+ },
+ },
+ },
+ },
+ MuiSvgIcon: {
+ styleOverrides: {
+ colorPrimary: {
+ fill: colorPalette.primary.main,
+ },
+ colorSecondary: {
+ fill: colorPalette.text.disabled,
+ },
+ },
+ },
+ MuiTableHead: {
+ styleOverrides: {
+ root: {
+ cursor: 'pointer',
+ },
+ },
+ },
+ MuiTooltip: {
+ styleOverrides: {
+ tooltip: {
+ fontSize: 'inherit',
+ backgroundColor: colorPalette.white,
+ boxShadow: 'rgba(99, 99, 99, 0.2) 0px 2px 8px 0px',
+ color: colorPalette.text.primary,
+ },
+ },
+ },
+ MuiDrawer: {
+ styleOverrides: {
+ root: {
+ zIndex: 50,
+ },
+ },
+ },
+ MuiOutlinedInput: {
+ styleOverrides: {
+ notchedOutline: {
+ borderColor: colorPalette.primary.main,
+ },
+ },
+ },
+ MuiAccordionSummary: {
+ styleOverrides: {
+ root: {
+ padding: '24px',
+ },
+ },
+ },
+ MuiAccordionDetails: {
+ styleOverrides: {
+ root: {
+ padding: '0 24px 24px 24px',
+ },
+ },
+ },
+ MuiAccordion: {
+ styleOverrides: {
+ gutters: {
+ borderRadius: '20px',
+ border: '1px',
+ },
+ root: {
+ boxShadow: 'none',
+ borderRadius: '16px !important',
+ border: 'solid 1px rgba(218, 222, 240, 0.8) !important',
+ },
+ },
+ },
+ MuiDialog: {
+ styleOverrides: {
+ paper: {
+ borderRadius: '20px',
+ },
+ root: {
+ zIndex: 20,
+ },
+ },
+ },
+ },
+ breakpoints: {
+ values: {
+ xs: 0,
+ sm: 600,
+ md: 900,
+ lg: 1285,
+ xl: 1536,
+ },
+ },
+ palette: colorPalette,
+};
diff --git a/packages/apps/human-app/frontend/src/test-utils/render-with-wrapper.tsx b/packages/apps/human-app/frontend/src/test-utils/render-with-wrapper.tsx
new file mode 100644
index 0000000000..18ae3669ee
--- /dev/null
+++ b/packages/apps/human-app/frontend/src/test-utils/render-with-wrapper.tsx
@@ -0,0 +1,16 @@
+import type { RenderOptions } from '@testing-library/react';
+import { render } from '@testing-library/react';
+import { BrowserRouter } from 'react-router-dom';
+import type { ReactElement, ReactNode } from 'react';
+
+//custom wrapper from official documentation https://testing-library.com/docs/react-testing-library/setup/
+export function renderWithWrapper(
+ ui: ReactElement,
+ options?: Omit
+) {
+ function Wrapper({ children }: { children: ReactNode }) {
+ return {children} ;
+ }
+
+ return render(ui, { wrapper: Wrapper, ...options });
+}
diff --git a/packages/apps/human-app/frontend/tsconfig.json b/packages/apps/human-app/frontend/tsconfig.json
new file mode 100644
index 0000000000..61f36395e7
--- /dev/null
+++ b/packages/apps/human-app/frontend/tsconfig.json
@@ -0,0 +1,34 @@
+{
+ "extends": "../../../../tsconfig.json",
+ "compilerOptions": {
+ "useDefineForClassFields": true,
+ "module": "Preserve",
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
+ "types": [
+ "vite-plugin-svgr/client",
+ "vite/client",
+ "vitest/globals",
+ "@testing-library/jest-dom"
+ ],
+ "strictNullChecks": true,
+
+ /* Bundler mode */
+ "moduleResolution": "bundler",
+ "allowImportingTsExtensions": false,
+ "isolatedModules": true,
+ "noEmit": true,
+ "jsx": "react-jsx",
+
+ /* Linting */
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "noFallthroughCasesInSwitch": true,
+ /* Absolute paths */
+ "baseUrl": ".",
+ "paths": {
+ "@/*": ["./src/*"]
+ }
+ },
+ "include": ["src/**/*.ts", "src/**/*.tsx"],
+ "references": [{ "path": "./tsconfig.node.json" }]
+}
diff --git a/packages/apps/human-app/frontend/tsconfig.node.json b/packages/apps/human-app/frontend/tsconfig.node.json
new file mode 100644
index 0000000000..a099f122a4
--- /dev/null
+++ b/packages/apps/human-app/frontend/tsconfig.node.json
@@ -0,0 +1,11 @@
+{
+ "compilerOptions": {
+ "strict": true,
+ "composite": true,
+ "skipLibCheck": true,
+ "module": "ESNext",
+ "moduleResolution": "bundler",
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["vite.config.ts"]
+}
diff --git a/packages/apps/human-app/frontend/vite.config.mjs b/packages/apps/human-app/frontend/vite.config.mjs
new file mode 100644
index 0000000000..3fc62ebc98
--- /dev/null
+++ b/packages/apps/human-app/frontend/vite.config.mjs
@@ -0,0 +1,35 @@
+import path from 'node:path';
+import { defineConfig } from 'vitest/config';
+import react from '@vitejs/plugin-react';
+import svgr from 'vite-plugin-svgr';
+
+// https://vitejs.dev/config/
+const config = defineConfig({
+ plugins: [
+ react(),
+ svgr({
+ include: '**/*.svg',
+ }),
+ ],
+ resolve: {
+ alias: {
+ '@': path.resolve(__dirname, './src'),
+ },
+ },
+ test: {
+ environment: 'jsdom',
+ globals: true,
+ includeSource: ['./src/**/*.{ts,tsx}'],
+ setupFiles: ['./src/setup-tests.ts/'],
+ },
+ build: {
+ target: 'esnext',
+ },
+ server: {
+ host: '127.0.0.1',
+ port: 3001
+ }
+});
+
+// eslint-disable-next-line import/no-default-export -- export vite config
+export default config;
diff --git a/packages/apps/human-app/server/.env.example b/packages/apps/human-app/server/.env.example
index 17951d7812..3af52d2c98 100644
--- a/packages/apps/human-app/server/.env.example
+++ b/packages/apps/human-app/server/.env.example
@@ -4,16 +4,27 @@ REPUTATION_ORACLE_URL= # string
REPUTATION_ORACLE_ADDRESS= # string
REDIS_HOST= # string, example: localhost
REDIS_PORT= # number, example: 6379
+RPC_URL= # string
+CHAIN_IDS_ENABLED= # number array, example: 80002,80001
+HCAPTCHA_LABELING_STATS_API_URL= # string
+HCAPTCHA_LABELING_VERIFY_API_URL= # string
+HCAPTCHA_LABELING_API_KEY= # string
+IS_AXIOS_REQUEST_LOGGING_ENABLED= #string, true if enabled, disabled otherwise
+# CACHE TTL VALUES - in seconds
CACHE_TTL_ORACLE_DISCOVERY= # number, example: 43200
CACHE_TTL_ORACLE_STATS= # number, example: 900
CACHE_TTL_USER_STATS= # number, example: 86400
+CACHE_TTL_EXCHANGE_ORACLE_URL= # number: example 86400
+CACHE_TTL_HCAPTCHA_USER_STATS= # number: example 86400
+CACHE_TTL_DAILY_HMT_SPENT= # number: example 86400
+# E2E TESTING
E2E_TESTING_EMAIL_ADDRESS= # string
E2E_TESTING_PASSWORD= # string
E2E_TESTING_EXCHANGE_ORACLE_URL= # string
E2E_TESTING_ESCROW_ADDRESS= # string
E2E_TESTING_ESCROW_CHAIN_ID= # number
-RPC_URL= # string
-CORS_ENABLED= # boolean, example: true
+# CORS
CORS_ALLOWED_ORIGIN= # string example: http://localhost:5173
-CORS_ALLOWED_HEADERS= # string, example: 'Content-Type,Accept'
-CHAIN_IDS_ENABLED= # number array, example: 80002,80001
\ No newline at end of file
+CORS_ALLOWED_HEADERS= # string, example: 'Content-Type,Authorization,X-Requested-With,Accept,Origin'
+CORS_ENABLED= # boolean, example: true
+IS_CACHE_TO_RESTART= # boolean, example: false
diff --git a/packages/apps/human-app/server/README.md b/packages/apps/human-app/server/README.md
index a90a442909..a7e4faa470 100644
--- a/packages/apps/human-app/server/README.md
+++ b/packages/apps/human-app/server/README.md
@@ -69,9 +69,28 @@ Models are used to define the shape and responsibilities of the data:
### Additional Information Regarding Project Structure
-- **Mappers**: There are two types of mappers. The first type is domain-specific, used in each module
-to distinguish between DTO and Command datatypes. The second type is layer-specific and part of gateway integration.
-This division of responsibilities is intentional, as gateways serve as the gathering point between many domain purposes.
-Domain-specific mappers in this context would be overly convoluted and difficult to configure.
-- **Gateway Configuration**: The configuration of the gateways' destination points is located
-in the `gateway-config.service.ts` file.
\ No newline at end of file
+ - **Mappers**: There are two types of mappers. The first type is domain-specific, used in each module
+ to distinguish between DTO and Command datatypes. The second type is layer-specific and part of gateway integration.
+ This division of responsibilities is intentional, as gateways serve as the gathering point between many domain purposes.
+ Domain-specific mappers in this context would be overly convoluted and difficult to configure.
+ - **Gateway Configuration**: The configuration of the gateways' destination points is located
+ in the `gateway-config.service.ts` file.
+ - **Caching**: Cache persistence functionality was introduced in this project for optimization purposes. Redis was chosen
+ as the in-memory storage. The TTL can be checked and changed in the `.env.example` file, all `TTL` values are in seconds:
+ * `REDIS_HOST` - URL of the Redis host
+ * `REDIS_PORT` - port on which Redis is hosted
+ * `CACHE_TTL_ORACLE_DISCOVERY` - time of persisting found oracles
+ * `CACHE_TTL_ORACLE_STATS` - time of persisting statistics of the given oracle
+ * `CACHE_TTL_DAILY_HMT_SPENT` - time of persisting statistics of global daily HMT expenditures
+ * `CACHE_TTL_USER_STATS` - time of persisting statistics of the given user
+ * `CACHE_TTL_HCAPTCHA_USER_STATS` - time of persisting statistics related to h-captcha tasks for given user
+ * `CACHE_TTL_EXCHANGE_ORACLE_URL` - time of persisting exchange oracle URL
+
+ Caching is used for persisting the exchange oracle URL as well as responses from the following endpoints:
+ * `/h-captcha/daily-hmt-spent`
+ * `/h-captcha/user-stats`
+ * `/oracles`
+ * `/statistics/stats`
+ * `/statistics/stats/assignment`
+
+ Redis config may be found in: `./packages/apps/human-app/server/src/common/config/cache-factory.config.ts`
diff --git a/packages/apps/human-app/server/package.json b/packages/apps/human-app/server/package.json
index 282af7ddfe..4b041d9047 100644
--- a/packages/apps/human-app/server/package.json
+++ b/packages/apps/human-app/server/package.json
@@ -11,7 +11,7 @@
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
- "start:prod": "node dist/main",
+ "start:prod": "node dist/src/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
@@ -24,12 +24,14 @@
"@automapper/core": "^8.8.1",
"@automapper/nestjs": "^8.8.1",
"@human-protocol/sdk": "*",
- "@nestjs/axios": "^2.0.0",
+ "@nestjs/axios": "^3.0.2",
"@nestjs/cache-manager": "^2.2.1",
"@nestjs/common": "^10.2.7",
"@nestjs/config": "^3.1.1",
- "@nestjs/core": "^10.2.8",
- "@nestjs/platform-express": "^10.3.8",
+ "@nestjs/core": "^10.3.10",
+ "@nestjs/platform-express": "^10.3.9",
+ "@nestjs/jwt": "^10.2.0",
+ "@nestjs/passport": "^10.0.3",
"@nestjs/swagger": "^7.1.13",
"cache-manager": "^5.4.0",
"cache-manager-redis-store": "^3.0.1",
@@ -37,18 +39,21 @@
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"ethers": "^6.12.1",
- "joi": "^17.12.2",
- "reflect-metadata": "^0.1.13",
- "rxjs": "^7.2.0"
+ "joi": "^17.13.3",
+ "reflect-metadata": "^0.2.2",
+ "rxjs": "^7.2.0",
+ "passport": "^0.7.0",
+ "passport-jwt": "^4.0.1"
},
"devDependencies": {
"@nestjs/cli": "^10.3.2",
- "@nestjs/schematics": "^9.2.0",
+ "@nestjs/schematics": "^10.1.3",
"@nestjs/testing": "^9.4.3",
"@types/express": "^4.17.13",
"@types/jest": "29.5.12",
"@types/node": "20.12.12",
"@types/supertest": "^2.0.15",
+ "@types/passport-jwt": "^4.0.1",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@typescript-eslint/parser": "^5.0.0",
"eslint": "^8.55.0",
@@ -58,8 +63,8 @@
"nock": "^13.5.1",
"prettier": "^3.1.1",
"source-map-support": "^0.5.20",
- "supertest": "^6.1.3",
- "ts-jest": "29.1.1",
+ "supertest": "^7.0.0",
+ "ts-jest": "29.2.2",
"ts-loader": "^9.2.3",
"ts-node": "^10.9.2",
"tsconfig-paths": "4.2.0",
diff --git a/packages/apps/human-app/server/src/app.module.ts b/packages/apps/human-app/server/src/app.module.ts
index c7199a0ed4..83856b1177 100644
--- a/packages/apps/human-app/server/src/app.module.ts
+++ b/packages/apps/human-app/server/src/app.module.ts
@@ -27,9 +27,17 @@ import { PasswordResetModule } from './modules/password-reset/password-reset.mod
import { DisableOperatorModule } from './modules/disable-operator/disable-operator.module';
import { KycProcedureModule } from './modules/kyc-procedure/kyc-procedure.module';
import { PrepareSignatureModule } from './modules/prepare-signature/prepare-signature.module';
+import { HCaptchaModule } from './modules/h-captcha/h-captcha.module';
+import { HCaptchaLabelingModule } from './integrations/h-captcha-labeling/h-captcha-labeling.module';
+import { HCaptchaController } from './modules/h-captcha/h-captcha.controller';
import { EscrowUtilsModule } from './integrations/escrow/escrow-utils.module';
import Joi from 'joi';
import { ChainId } from '@human-protocol/sdk';
+import { RegisterAddressController } from './modules/register-address/register-address.controller';
+import { RegisterAddressModule } from './modules/register-address/register-address.module';
+import { InterceptorModule } from './common/interceptors/interceptor.module';
+import { TokenRefreshModule } from './modules/token-refresh/token-refresh.module';
+import { TokenRefreshController } from './modules/token-refresh/token-refresh.controller';
@Module({
imports: [
@@ -44,6 +52,9 @@ import { ChainId } from '@human-protocol/sdk';
REDIS_PORT: Joi.number().required(),
REDIS_HOST: Joi.string().required(),
RPC_URL: Joi.string().required(),
+ HCAPTCHA_LABELING_STATS_API_URL: Joi.string().required(),
+ HCAPTCHA_LABELING_VERIFY_API_URL: Joi.string().required(),
+ HCAPTCHA_LABELING_API_KEY: Joi.string().required(),
CHAIN_IDS_ENABLED: Joi.string()
.custom((value) => {
const chainIds = value.split(',');
@@ -79,7 +90,12 @@ import { ChainId } from '@human-protocol/sdk';
DisableOperatorModule,
KycProcedureModule,
PrepareSignatureModule,
+ HCaptchaModule,
+ HCaptchaLabelingModule,
EscrowUtilsModule,
+ RegisterAddressModule,
+ InterceptorModule,
+ TokenRefreshModule,
],
controllers: [
AppController,
@@ -89,6 +105,9 @@ import { ChainId } from '@human-protocol/sdk';
OracleDiscoveryController,
JobAssignmentController,
StatisticsController,
+ HCaptchaController,
+ RegisterAddressController,
+ TokenRefreshController,
],
exports: [HttpModule],
})
diff --git a/packages/apps/human-app/server/src/common/config/environment-config.service.ts b/packages/apps/human-app/server/src/common/config/environment-config.service.ts
index 99de8b5674..80e23c3cfc 100644
--- a/packages/apps/human-app/server/src/common/config/environment-config.service.ts
+++ b/packages/apps/human-app/server/src/common/config/environment-config.service.ts
@@ -1,10 +1,14 @@
import { ConfigService } from '@nestjs/config';
import { Injectable } from '@nestjs/common';
+const DEFAULT_CACHE_TTL_HCAPTCHA_USER_STATS = 12 * 60 * 60;
const DEFAULT_CACHE_TTL_ORACLE_STATS = 12 * 60 * 60;
const DEFAULT_CACHE_TTL_USER_STATS = 15 * 60;
const DEFAULT_CACHE_TTL_ORACLE_DISCOVERY = 24 * 60 * 60;
+const DEFAULT_CACHE_TTL_DAILY_HMT_SPENT = 24 * 60 * 60;
const DEFAULT_CORS_ALLOWED_ORIGIN = 'http://localhost:5173';
-const DEFAULT_CORS_ALLOWED_HEADERS = 'Content-Type, Accept';
+const DEFAULT_CORS_ALLOWED_HEADERS =
+ 'Content-Type,Authorization,X-Requested-With,Accept,Origin';
+const DEFAULT_CACHE_TTL_EXCHANGE_ORACLE_URL = 24 * 60 * 60;
@Injectable()
export class EnvironmentConfigService {
constructor(private configService: ConfigService) {}
@@ -18,7 +22,14 @@ export class EnvironmentConfigService {
return this.configService.getOrThrow('REPUTATION_ORACLE_URL');
}
get reputationOracleAddress(): string {
- return this.configService.getOrThrow('REPUTATION_ORACLE_ADDRESS');
+ return this.configService
+ .getOrThrow