From 8490b96879185aa20bc80e4971bea812efe8e909 Mon Sep 17 00:00:00 2001 From: Nitin Mittal Date: Fri, 4 Aug 2023 18:45:55 +0400 Subject: [PATCH] new: migrate common package --- .github/CODEOWNERS | 1 + .github/pull_request_templates/PR_TEMPLATE.md | 30 + .github/workflows/tests.yml | 29 + .gitignore | 19 + babel.config.json | 16 + internal/block_getters/block_getter.ts | 117 + internal/block_getters/block_getter_worker.ts | 51 + internal/block_getters/erigon_block_getter.ts | 129 + .../erigon_block_getter_worker.ts | 51 + .../block_getters/quicknode_block_getter.ts | 76 + .../quicknode_block_getter_worker.ts | 51 + internal/block_producers/block_producer.ts | 363 + .../block_producers/produced_blocks_model.ts | 47 + .../abstract_block_subscription.ts | 293 + internal/block_subscription/block_polling.ts | 88 + .../block_subscription/block_subscription.ts | 225 + internal/coder/abi_coder.ts | 61 + internal/coder/protobuf_coder.ts | 117 + .../abstract_data_transformer.ts | 118 + internal/enums/bridgetype.ts | 8 + internal/enums/tokentype.ts | 11 + internal/errors/api_error.ts | 57 + internal/errors/base_error.ts | 32 + internal/errors/block_producer_error.ts | 57 + internal/errors/coder_error.ts | 29 + internal/errors/create_error_object.ts | 14 + internal/errors/error_codes.ts | 45 + internal/errors/event_consumer_error.ts | 57 + internal/errors/get_error_message.ts | 15 + internal/errors/is_base_error.ts | 15 + internal/errors/is_librdkafka_error.ts | 20 + internal/errors/kafka_error.ts | 80 + .../event_consumer/abstract_event_consumer.ts | 44 + internal/filter/bloom_filter.ts | 26 + internal/formatters/block_formatter.ts | 210 + internal/interfaces/async_observer.ts | 7 + internal/interfaces/block.ts | 25 + internal/interfaces/block_getter.ts | 8 + .../interfaces/block_getter_worker_promise.ts | 5 + internal/interfaces/block_header.ts | 16 + internal/interfaces/block_producer_config.ts | 12 + internal/interfaces/block_subscription.ts | 6 + internal/interfaces/block_worker_message.ts | 7 + internal/interfaces/coder.ts | 12 + internal/interfaces/coder_config.ts | 7 + internal/interfaces/common_kafka_events.ts | 36 + internal/interfaces/config.ts | 79 + internal/interfaces/consumer_config.ts | 19 + internal/interfaces/consumer_queue_object.ts | 4 + internal/interfaces/deposit.ts | 15 + .../interfaces/deserialised_kafka_message.ts | 5 + internal/interfaces/event_log.ts | 13 + internal/interfaces/index.ts | 36 + internal/interfaces/kafka_coder_config.ts | 5 + internal/interfaces/logger_config.ts | 17 + internal/interfaces/mapper.ts | 4 + internal/interfaces/new_heads_subscriber.ts | 6 + internal/interfaces/observer.ts | 5 + internal/interfaces/producer_config.ts | 15 + internal/interfaces/quicknode_response.ts | 7 + internal/interfaces/raw_block.ts | 24 + internal/interfaces/raw_receipt.ts | 27 + internal/interfaces/raw_transaction.ts | 15 + internal/interfaces/rpc_payload.ts | 4 + .../interfaces/sequential_consumer_config.ts | 6 + internal/interfaces/stream_api_block.ts | 68 + internal/interfaces/synchronous_producer.ts | 16 + internal/interfaces/transaction.ts | 25 + internal/interfaces/transaction_receipt.ts | 18 + internal/interfaces/transformed_block.ts | 7 + internal/interfaces/web3_transaction.ts | 9 + .../interfaces/web3_transaction_receipt.ts | 5 + internal/kafka/consumer/abstract_consumer.ts | 459 ++ .../kafka/consumer/asynchronous_consumer.ts | 50 + .../kafka/consumer/synchronous_consumer.ts | 24 + internal/kafka/producer/abstract_producer.ts | 267 + .../kafka/producer/asynchronous_producer.ts | 96 + .../kafka/producer/synchronous_producer.ts | 111 + internal/logger/logger.ts | 141 + internal/mongo/database.ts | 78 + internal/queue/queue.ts | 71 + internal/rpc/json_rpc_client.ts | 38 + jest.config.ts | 22 + .../block_producers/block_polling_producer.ts | 69 + .../block_producers/erigon_block_producer.ts | 82 + public/block_producers/produce_blocks.ts | 30 + .../quicknode_block_producer.ts | 84 + public/coder/abi_coder.ts | 1 + public/coder/protobuf_coder.ts | 1 + .../asynchronous_data_transformer.ts | 18 + .../synchronous_data_transformer.ts | 18 + public/enums/bridgetype.ts | 1 + public/enums/tokentype.ts | 1 + public/errors/api_error.ts | 1 + public/errors/base_error.ts | 1 + public/errors/block_producer_error.ts | 1 + public/errors/coder_error.ts | 1 + public/errors/create_error_object.ts | 1 + public/errors/error_codes.ts | 1 + public/errors/event_consumer_error.ts | 1 + public/errors/get_error_message.ts | 1 + public/errors/index.ts | 9 + public/errors/is_base_error.ts | 1 + public/errors/is_librdkafka_error.ts | 1 + public/errors/kafka_error.ts | 1 + .../event_consumer/abstract_event_consumer.ts | 1 + public/filter/bloom_filter.ts | 1 + public/index.ts | 56 + public/interfaces/async_observer.ts | 1 + public/interfaces/block.ts | 1 + public/interfaces/block_getter.ts | 1 + .../interfaces/block_getter_worker_promise.ts | 1 + public/interfaces/block_header.ts | 1 + public/interfaces/block_producer_config.ts | 1 + public/interfaces/block_subscription.ts | 1 + public/interfaces/block_worker_message.ts | 1 + public/interfaces/coder.ts | 1 + public/interfaces/coder_config.ts | 1 + public/interfaces/common_kafka_events.ts | 1 + public/interfaces/config.ts | 1 + public/interfaces/consumer_config.ts | 1 + public/interfaces/consumer_queue_object.ts | 1 + public/interfaces/deposit.ts | 1 + .../interfaces/deserialised_kafka_message.ts | 1 + public/interfaces/event_log.ts | 1 + public/interfaces/index.ts | 36 + public/interfaces/kafka_coder_config.ts | 1 + public/interfaces/logger_config.ts | 1 + public/interfaces/mapper.ts | 1 + public/interfaces/new_heads_subscriber.ts | 1 + public/interfaces/observer.ts | 1 + public/interfaces/producer_config.ts | 1 + public/interfaces/quicknode_response.ts | 1 + public/interfaces/raw_block.ts | 1 + public/interfaces/raw_receipt.ts | 1 + public/interfaces/raw_transaction.ts | 1 + public/interfaces/rpc_payload.ts | 1 + .../interfaces/sequential_consumer_config.ts | 1 + public/interfaces/stream_api_block.ts | 1 + public/interfaces/synchronous_producer.ts | 1 + public/interfaces/transaction.ts | 1 + public/interfaces/transaction_receipt.ts | 1 + public/interfaces/transformed_block.ts | 1 + public/interfaces/web3_transaction.ts | 1 + public/interfaces/web3_transaction_receipt.ts | 1 + .../kafka/consumer/asynchronous_consumer.ts | 1 + public/kafka/consumer/consume.ts | 68 + public/kafka/consumer/synchronous_consumer.ts | 1 + .../kafka/producer/asynchronous_producer.ts | 1 + public/kafka/producer/produce.ts | 54 + public/kafka/producer/synchronous_producer.ts | 1 + public/logger/logger.ts | 1 + public/mongo/database.ts | 1 + public/rpc/json_rpc_client.ts | 1 + schemas/block.proto | 27 + schemas/bridge_assets.proto | 44 + schemas/burnblock.proto | 20 + schemas/checkpointblock.proto | 21 + schemas/claim_assets.proto | 18 + schemas/depositblock.proto | 20 + schemas/eventlog.proto | 14 + schemas/l1_state.proto | 20 + schemas/mappings.proto | 22 + schemas/new_batch.proto | 9 + schemas/posmapping.proto | 18 + schemas/statesync.proto | 15 + schemas/test.proto | 9 + schemas/transaction.proto | 42 + schemas/withdrawblock.proto | 25 + tests/__mocks__/coder.js | 4 + tests/__mocks__/observer.js | 5 + tests/block_getters/block_getter.test.ts | 127 + .../block_getters/block_getter_worker.test.ts | 151 + .../block_getters/erigon_block_getter.test.ts | 223 + .../quicknode_block_getter.test.ts | 194 + tests/block_producer/block_producer.test.ts | 586 ++ .../quicknode_block_producer.test.ts | 156 + .../abstract_block_subscription.test.ts | 396 + .../block_subscription/block_polling.test.ts | 112 + .../block_subscription.test.ts | 379 + tests/coder/abi_coder.test.ts | 70 + tests/coder/protobuf_coder.test.ts | 153 + tests/errors/api_error.test.ts | 137 + tests/errors/base_error.test.ts | 48 + tests/errors/block_producer_error.test.ts | 138 + tests/errors/coder_error.test.ts | 69 + tests/errors/create_error_object.test.ts | 30 + tests/errors/event_consumer_error.test.ts | 140 + tests/errors/get_error_message.test.ts | 19 + tests/errors/kafka_error.test.ts | 285 + .../abstract_event_consumer.test.ts | 80 + tests/formatters/block_formatter.test.ts | 265 + .../kafka/consumer/abstract_consumer.test.ts | 668 ++ .../consumer/asynchronous_consumer.test.ts | 131 + .../consumer/synchronous_consumer.test.ts | 52 + .../kafka/producer/abstract_producer.test.ts | 284 + .../producer/asynchronous_producer.test.ts | 118 + .../producer/synchronous_producer.test.ts | 97 + tests/logger/logger.test.ts | 254 + tests/mock_data/block.js | 181 + tests/mock_data/connect_error.json | 8 + tests/mock_data/disconnected_error.json | 8 + tests/mock_data/ethereum_block.json | 120 + tests/mock_data/ethereum_full_block.json | 669 ++ .../ethereum_transaction_receipts.json | 257 + .../ethereum_transaction_receipts_array.json | 257 + tests/mock_data/log.json | 16 + tests/mock_data/metadata_mock.json | 28 + tests/mock_data/mock_message.json | 5 + tests/mock_data/polygon_block.json | 421 ++ tests/mock_data/raw_ethereum_block.json | 122 + tests/mock_data/zkevm_block.js | 221 + tests/queue/queue.test.ts | 102 + tsconfig.json | 25 + yarn.lock | 6390 +++++++++++++++++ 215 files changed, 19663 insertions(+) create mode 100644 .github/CODEOWNERS create mode 100644 .github/pull_request_templates/PR_TEMPLATE.md create mode 100644 .github/workflows/tests.yml create mode 100644 .gitignore create mode 100644 babel.config.json create mode 100644 internal/block_getters/block_getter.ts create mode 100644 internal/block_getters/block_getter_worker.ts create mode 100644 internal/block_getters/erigon_block_getter.ts create mode 100644 internal/block_getters/erigon_block_getter_worker.ts create mode 100644 internal/block_getters/quicknode_block_getter.ts create mode 100644 internal/block_getters/quicknode_block_getter_worker.ts create mode 100644 internal/block_producers/block_producer.ts create mode 100644 internal/block_producers/produced_blocks_model.ts create mode 100644 internal/block_subscription/abstract_block_subscription.ts create mode 100644 internal/block_subscription/block_polling.ts create mode 100644 internal/block_subscription/block_subscription.ts create mode 100644 internal/coder/abi_coder.ts create mode 100644 internal/coder/protobuf_coder.ts create mode 100644 internal/data_transformation/abstract_data_transformer.ts create mode 100644 internal/enums/bridgetype.ts create mode 100644 internal/enums/tokentype.ts create mode 100644 internal/errors/api_error.ts create mode 100644 internal/errors/base_error.ts create mode 100644 internal/errors/block_producer_error.ts create mode 100644 internal/errors/coder_error.ts create mode 100644 internal/errors/create_error_object.ts create mode 100644 internal/errors/error_codes.ts create mode 100644 internal/errors/event_consumer_error.ts create mode 100644 internal/errors/get_error_message.ts create mode 100644 internal/errors/is_base_error.ts create mode 100644 internal/errors/is_librdkafka_error.ts create mode 100644 internal/errors/kafka_error.ts create mode 100644 internal/event_consumer/abstract_event_consumer.ts create mode 100644 internal/filter/bloom_filter.ts create mode 100644 internal/formatters/block_formatter.ts create mode 100644 internal/interfaces/async_observer.ts create mode 100644 internal/interfaces/block.ts create mode 100644 internal/interfaces/block_getter.ts create mode 100644 internal/interfaces/block_getter_worker_promise.ts create mode 100644 internal/interfaces/block_header.ts create mode 100644 internal/interfaces/block_producer_config.ts create mode 100644 internal/interfaces/block_subscription.ts create mode 100644 internal/interfaces/block_worker_message.ts create mode 100644 internal/interfaces/coder.ts create mode 100644 internal/interfaces/coder_config.ts create mode 100644 internal/interfaces/common_kafka_events.ts create mode 100644 internal/interfaces/config.ts create mode 100644 internal/interfaces/consumer_config.ts create mode 100644 internal/interfaces/consumer_queue_object.ts create mode 100644 internal/interfaces/deposit.ts create mode 100644 internal/interfaces/deserialised_kafka_message.ts create mode 100644 internal/interfaces/event_log.ts create mode 100644 internal/interfaces/index.ts create mode 100644 internal/interfaces/kafka_coder_config.ts create mode 100644 internal/interfaces/logger_config.ts create mode 100644 internal/interfaces/mapper.ts create mode 100644 internal/interfaces/new_heads_subscriber.ts create mode 100644 internal/interfaces/observer.ts create mode 100644 internal/interfaces/producer_config.ts create mode 100644 internal/interfaces/quicknode_response.ts create mode 100644 internal/interfaces/raw_block.ts create mode 100644 internal/interfaces/raw_receipt.ts create mode 100644 internal/interfaces/raw_transaction.ts create mode 100644 internal/interfaces/rpc_payload.ts create mode 100644 internal/interfaces/sequential_consumer_config.ts create mode 100644 internal/interfaces/stream_api_block.ts create mode 100644 internal/interfaces/synchronous_producer.ts create mode 100644 internal/interfaces/transaction.ts create mode 100644 internal/interfaces/transaction_receipt.ts create mode 100644 internal/interfaces/transformed_block.ts create mode 100644 internal/interfaces/web3_transaction.ts create mode 100644 internal/interfaces/web3_transaction_receipt.ts create mode 100644 internal/kafka/consumer/abstract_consumer.ts create mode 100644 internal/kafka/consumer/asynchronous_consumer.ts create mode 100644 internal/kafka/consumer/synchronous_consumer.ts create mode 100644 internal/kafka/producer/abstract_producer.ts create mode 100644 internal/kafka/producer/asynchronous_producer.ts create mode 100644 internal/kafka/producer/synchronous_producer.ts create mode 100644 internal/logger/logger.ts create mode 100644 internal/mongo/database.ts create mode 100644 internal/queue/queue.ts create mode 100644 internal/rpc/json_rpc_client.ts create mode 100644 jest.config.ts create mode 100644 public/block_producers/block_polling_producer.ts create mode 100644 public/block_producers/erigon_block_producer.ts create mode 100644 public/block_producers/produce_blocks.ts create mode 100644 public/block_producers/quicknode_block_producer.ts create mode 100644 public/coder/abi_coder.ts create mode 100644 public/coder/protobuf_coder.ts create mode 100644 public/data_transformation/asynchronous_data_transformer.ts create mode 100644 public/data_transformation/synchronous_data_transformer.ts create mode 100644 public/enums/bridgetype.ts create mode 100644 public/enums/tokentype.ts create mode 100644 public/errors/api_error.ts create mode 100644 public/errors/base_error.ts create mode 100644 public/errors/block_producer_error.ts create mode 100644 public/errors/coder_error.ts create mode 100644 public/errors/create_error_object.ts create mode 100644 public/errors/error_codes.ts create mode 100644 public/errors/event_consumer_error.ts create mode 100644 public/errors/get_error_message.ts create mode 100644 public/errors/index.ts create mode 100644 public/errors/is_base_error.ts create mode 100644 public/errors/is_librdkafka_error.ts create mode 100644 public/errors/kafka_error.ts create mode 100644 public/event_consumer/abstract_event_consumer.ts create mode 100644 public/filter/bloom_filter.ts create mode 100644 public/index.ts create mode 100644 public/interfaces/async_observer.ts create mode 100644 public/interfaces/block.ts create mode 100644 public/interfaces/block_getter.ts create mode 100644 public/interfaces/block_getter_worker_promise.ts create mode 100644 public/interfaces/block_header.ts create mode 100644 public/interfaces/block_producer_config.ts create mode 100644 public/interfaces/block_subscription.ts create mode 100644 public/interfaces/block_worker_message.ts create mode 100644 public/interfaces/coder.ts create mode 100644 public/interfaces/coder_config.ts create mode 100644 public/interfaces/common_kafka_events.ts create mode 100644 public/interfaces/config.ts create mode 100644 public/interfaces/consumer_config.ts create mode 100644 public/interfaces/consumer_queue_object.ts create mode 100644 public/interfaces/deposit.ts create mode 100644 public/interfaces/deserialised_kafka_message.ts create mode 100644 public/interfaces/event_log.ts create mode 100644 public/interfaces/index.ts create mode 100644 public/interfaces/kafka_coder_config.ts create mode 100644 public/interfaces/logger_config.ts create mode 100644 public/interfaces/mapper.ts create mode 100644 public/interfaces/new_heads_subscriber.ts create mode 100644 public/interfaces/observer.ts create mode 100644 public/interfaces/producer_config.ts create mode 100644 public/interfaces/quicknode_response.ts create mode 100644 public/interfaces/raw_block.ts create mode 100644 public/interfaces/raw_receipt.ts create mode 100644 public/interfaces/raw_transaction.ts create mode 100644 public/interfaces/rpc_payload.ts create mode 100644 public/interfaces/sequential_consumer_config.ts create mode 100644 public/interfaces/stream_api_block.ts create mode 100644 public/interfaces/synchronous_producer.ts create mode 100644 public/interfaces/transaction.ts create mode 100644 public/interfaces/transaction_receipt.ts create mode 100644 public/interfaces/transformed_block.ts create mode 100644 public/interfaces/web3_transaction.ts create mode 100644 public/interfaces/web3_transaction_receipt.ts create mode 100644 public/kafka/consumer/asynchronous_consumer.ts create mode 100644 public/kafka/consumer/consume.ts create mode 100644 public/kafka/consumer/synchronous_consumer.ts create mode 100644 public/kafka/producer/asynchronous_producer.ts create mode 100644 public/kafka/producer/produce.ts create mode 100644 public/kafka/producer/synchronous_producer.ts create mode 100644 public/logger/logger.ts create mode 100644 public/mongo/database.ts create mode 100644 public/rpc/json_rpc_client.ts create mode 100644 schemas/block.proto create mode 100644 schemas/bridge_assets.proto create mode 100644 schemas/burnblock.proto create mode 100644 schemas/checkpointblock.proto create mode 100644 schemas/claim_assets.proto create mode 100644 schemas/depositblock.proto create mode 100644 schemas/eventlog.proto create mode 100644 schemas/l1_state.proto create mode 100644 schemas/mappings.proto create mode 100644 schemas/new_batch.proto create mode 100644 schemas/posmapping.proto create mode 100644 schemas/statesync.proto create mode 100644 schemas/test.proto create mode 100644 schemas/transaction.proto create mode 100644 schemas/withdrawblock.proto create mode 100644 tests/__mocks__/coder.js create mode 100644 tests/__mocks__/observer.js create mode 100644 tests/block_getters/block_getter.test.ts create mode 100644 tests/block_getters/block_getter_worker.test.ts create mode 100644 tests/block_getters/erigon_block_getter.test.ts create mode 100644 tests/block_getters/quicknode_block_getter.test.ts create mode 100644 tests/block_producer/block_producer.test.ts create mode 100644 tests/block_producer/quicknode_block_producer.test.ts create mode 100644 tests/block_subscription/abstract_block_subscription.test.ts create mode 100644 tests/block_subscription/block_polling.test.ts create mode 100644 tests/block_subscription/block_subscription.test.ts create mode 100644 tests/coder/abi_coder.test.ts create mode 100644 tests/coder/protobuf_coder.test.ts create mode 100644 tests/errors/api_error.test.ts create mode 100644 tests/errors/base_error.test.ts create mode 100644 tests/errors/block_producer_error.test.ts create mode 100644 tests/errors/coder_error.test.ts create mode 100644 tests/errors/create_error_object.test.ts create mode 100644 tests/errors/event_consumer_error.test.ts create mode 100644 tests/errors/get_error_message.test.ts create mode 100644 tests/errors/kafka_error.test.ts create mode 100644 tests/event_consumer/abstract_event_consumer.test.ts create mode 100644 tests/formatters/block_formatter.test.ts create mode 100644 tests/kafka/consumer/abstract_consumer.test.ts create mode 100644 tests/kafka/consumer/asynchronous_consumer.test.ts create mode 100644 tests/kafka/consumer/synchronous_consumer.test.ts create mode 100644 tests/kafka/producer/abstract_producer.test.ts create mode 100644 tests/kafka/producer/asynchronous_producer.test.ts create mode 100644 tests/kafka/producer/synchronous_producer.test.ts create mode 100644 tests/logger/logger.test.ts create mode 100644 tests/mock_data/block.js create mode 100644 tests/mock_data/connect_error.json create mode 100644 tests/mock_data/disconnected_error.json create mode 100644 tests/mock_data/ethereum_block.json create mode 100644 tests/mock_data/ethereum_full_block.json create mode 100644 tests/mock_data/ethereum_transaction_receipts.json create mode 100644 tests/mock_data/ethereum_transaction_receipts_array.json create mode 100644 tests/mock_data/log.json create mode 100644 tests/mock_data/metadata_mock.json create mode 100644 tests/mock_data/mock_message.json create mode 100644 tests/mock_data/polygon_block.json create mode 100644 tests/mock_data/raw_ethereum_block.json create mode 100644 tests/mock_data/zkevm_block.js create mode 100644 tests/queue/queue.test.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..1cb3187 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @maticnetwork/product-applications diff --git a/.github/pull_request_templates/PR_TEMPLATE.md b/.github/pull_request_templates/PR_TEMPLATE.md new file mode 100644 index 0000000..7978f94 --- /dev/null +++ b/.github/pull_request_templates/PR_TEMPLATE.md @@ -0,0 +1,30 @@ +## Type of change + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +## Bug/Feature Description +Clearly and concisely describe the problem. + +## Root cause +Briefly describe the root cause and analysis of the problem. + +## Solution Description +Describe your code changes in detail for reviewers. Explain the technical solution you have provided and how it fixes the issue case. + +## Covered unit tests +Were unit test cases recorded for this fix or was only manual testing applicable? +[ ] I have extended, updated or written new tests for the related code changes/additions. + +## Before requesting review +- [ ] Are github workflows showing build acceptance? +- [ ] I have selected the correct base branch. +- [ ] I have performed a self-review of my own code. +- [ ] I have commented my code, particularly in hard-to-understand areas. +- [ ] I have made corresponding changes to the documentation. +- [ ] My changes generate no new warnings. +- [ ] Any dependent changes have been merged and published in downstream modules. +- [ ] I have updated the ``CHANGELOG.md`` file in the root folder. +- [ ] I have tested my code locally in the development environemnt. \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..4807892 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,29 @@ +name: Tests +run-name: ${{ github.actor }} just pushed to ChainFlow + +on: + push: + branches: + - '**' + +jobs: + Tests: + name: Tests + runs-on: ubuntu-latest + steps: + - name: CHECK-OUT GIT REPOSITORY + uses: actions/checkout@v3 + - name: Use Node.js (v14) + uses: actions/setup-node@v3 + with: + node-version: '14' + - name: Check ubuntu version + run: lsb_release -a + - name: Install dependencies + run: yarn + - name: Build Packages + run: yarn run build + - name: Run Unit Tests + run: yarn run tests + - name: Run Integration Tests + run: yarn tests:integration diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..870dc17 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +node_modules/ +build/ +dist/ +coverage/ +.env +logs/ +*.log +.DS_Store +*.rdb +.idea/ +package-lock.json +.vscode +.env.local +*.key +*.cert +pids/ + +#packages/services/producers/ethereum/taskdef +#Dockerfile.ethereum-producer diff --git a/babel.config.json b/babel.config.json new file mode 100644 index 0000000..d78498b --- /dev/null +++ b/babel.config.json @@ -0,0 +1,16 @@ +{ + "presets": [ + [ + "@babel/preset-env", + { + "targets": { + "node": "current" + } + } + ], + "@babel/preset-typescript" + ], + "plugins": [ + "babel-plugin-transform-import-meta" + ] +} diff --git a/internal/block_getters/block_getter.ts b/internal/block_getters/block_getter.ts new file mode 100644 index 0000000..c18573a --- /dev/null +++ b/internal/block_getters/block_getter.ts @@ -0,0 +1,117 @@ +import { Block, BlockTransactionObject, Eth, TransactionReceipt } from "web3-eth"; +import { ITransactionReceipt } from "../interfaces/transaction_receipt.js"; +import { BlockProducerError } from "../errors/block_producer_error.js"; +import { IWeb3Transaction } from "../interfaces/web3_transaction.js"; +import { BlockFormatter } from "../formatters/block_formatter.js"; +import { ITransaction } from "../interfaces/transaction.js"; +import { IBlock } from "../interfaces/block.js"; +import { IBlockGetter } from "../interfaces/block_getter.js"; +import { Logger } from "../logger/logger.js"; + +/** + * A wrapper class on web3 block related functions + * + * @author - Vibhu Rajeev, Nitin Mittal + */ +export class BlockGetter extends BlockFormatter implements IBlockGetter { + /** + * @param {Eth} eth - Eth module from web3.js + * @param {number} maxRetries - The number of times to retry on errors. + * + * @constructor + */ + constructor(protected eth: Eth, protected maxRetries: number = 0) { + super(); + } + + /** + * @async + * Public method to query block data of a single block + * + * @param {number | string} blockNumber - Block number to query the block details for. + * + * @returns {Promise} - Block object + */ + public async getBlock(blockNumber: number | string): Promise { + return await this.eth.getBlock(blockNumber); + } + + /** + * @async + * Public method to query block data including transaction receipts of a single block. + * + * @param {number | string} blockNumber - The block number for which block data needs to be retrieved. + * + * @returns {Promise} - Block object containing all details including transaction receipts. + * + * @throws {Error} - Throws error object on failure. + */ + public async getBlockWithTransactionReceipts(blockNumber: number | string): Promise { + const block: BlockTransactionObject = await this.eth.getBlock(blockNumber, true); + Logger.debug(`Fetching transaction receipts for the following block ${block.number}`); + + const transactions: ITransaction[] = []; + + for (const transactionObject of block.transactions) { + transactions.push( + this.formatTransactionObject( + transactionObject as IWeb3Transaction, + await this.getTransactionReceipt(transactionObject.hash) + ) + ); + } + + return this.formatBlockWithTransactions( + block as BlockTransactionObject, + transactions + ); + } + + /** + * @async + * Public method to query the current block number. + * + * @returns {Promise} - the current block. + * + * @throws {Error} - Throws error object on failure. + */ + public getLatestBlockNumber(): Promise { + return this.eth.getBlockNumber(); + } + + /** + * @async + * This internal method retrieves the transaction receipt of the given transaction hash and retries upto retryLimit on failure. + * + * @param {string} transactionHash - The transaction hash for which transaction receipt is to be retrieved. + * @param {number} errorCount - Parameter for the function to know the number of times query has been retried. + * This parameter must ideally not be set by an external call. + * + * @returns {Promise} - The transaction receipt of the given transaction hash. On failure throws error object. + * + * @throws {Error} - Throws error object on failure. + */ + protected async getTransactionReceipt(transactionHash: string, errorCount: number = 0): Promise { + try { + const transactionReceipt: TransactionReceipt = await this.eth.getTransactionReceipt(transactionHash); + + if (transactionReceipt === null) { + throw new BlockProducerError( + "Block producer error", + BlockProducerError.codes.RECEIPT_NOT_FOUND, + false, + `Transaction receipt not found for ${transactionHash}.`, + "remote" + ); + } + + return this.formatTransactionReceipt(transactionReceipt); + } catch (error) { + if (errorCount >= this.maxRetries) { + throw error; + } + + return this.getTransactionReceipt(transactionHash, errorCount + 1); + } + } +} diff --git a/internal/block_getters/block_getter_worker.ts b/internal/block_getters/block_getter_worker.ts new file mode 100644 index 0000000..37faf2d --- /dev/null +++ b/internal/block_getters/block_getter_worker.ts @@ -0,0 +1,51 @@ +import { IBlockWorkerMessage } from "../interfaces/block_worker_message.js"; +import { parentPort, workerData } from "worker_threads"; +import { BlockGetter } from "./block_getter.js"; +import EthClass from "web3-eth"; + +if (!workerData || !parentPort) { + process.exit(1); +} + +const blockGetter = new BlockGetter( + //@ts-ignore + new EthClass( + //@ts-ignore + new EthClass.providers.WebsocketProvider( + workerData.endpoint, + { + reconnect: { + auto: true + }, + clientConfig: { + maxReceivedFrameSize: 1000000000, + maxReceivedMessageSize: 1000000000, + }, + timeout: 45000 + } + ) + ), + workerData.maxRetries +); + +parentPort.on("message", async (message: { + blockNumber: number, + callBackId: number +}) => { + try { + parentPort?.postMessage( + { + callBackId: message.callBackId, + error: null, + block: await blockGetter.getBlockWithTransactionReceipts(message.blockNumber) + } as IBlockWorkerMessage + ); + } catch (error) { + parentPort?.postMessage( + { + callBackId: message.callBackId, + error: error + } as IBlockWorkerMessage + ); + } +}); diff --git a/internal/block_getters/erigon_block_getter.ts b/internal/block_getters/erigon_block_getter.ts new file mode 100644 index 0000000..f00ff7f --- /dev/null +++ b/internal/block_getters/erigon_block_getter.ts @@ -0,0 +1,129 @@ +import utils from "web3-utils"; +import { WebsocketProvider } from "web3-core"; +import { BlockTransactionObject } from "web3-eth"; +import { ITransaction } from "../interfaces/transaction.js"; +import { IBlock } from "../interfaces/block.js"; +import { BlockGetter } from "./block_getter.js"; +import { IBlockGetter } from "../interfaces/block_getter.js"; +import { IRawReceipt } from "../interfaces/raw_receipt.js"; +import { IWeb3Transaction } from "../interfaces/web3_transaction.js"; + +/** + * A wrapper class on web3 to get blocks from erigon nodes and format them. + * + * @author - Vibhu Rajeev + */ +export class ErigonBlockGetter extends BlockGetter implements IBlockGetter { + + /** + * @async + * Public method to query block data including transaction receipts of a single block. + * + * @param {number | string} blockNumber - The block number for which block data needs to be retrieved. + * @param {number} retryCount - The amount of retries it should. Defaults to 0. + * + * @returns {Promise} - Block object containing all details including transaction receipts. + * + * @throws {Error} - Throws error object on failure. + */ + public async getBlockWithTransactionReceipts(blockNumber: number | string, retryCount: number = 0): Promise { + try { + const result: [BlockTransactionObject, IRawReceipt[]] = await Promise.all([ + this.eth.getBlock(blockNumber, true), + this.getTransactionReceipts(blockNumber) + ]); + + const transactions: ITransaction[] = []; + + for (const transactionObject of result[0].transactions) { + transactions.push(this.formatTransactionObject( + transactionObject as IWeb3Transaction, + this.formatRawReceipt(result[1].find( + (receipt) => receipt.transactionHash === transactionObject.hash + )) ?? + await this.getTransactionReceipt(transactionObject.hash) + )); + } + + return this.formatBlockWithTransactions( + result[0], + transactions + ); + } catch (error) { + if (retryCount < this.maxRetries) { + return this.getBlockWithTransactionReceipts( + blockNumber, + retryCount + 1 + ); + } + + throw error; + } + } + + /** + * @private + * + * Private method to get all transaction receipts for a block. + * + * @param {number | string} blockNumber - Block number for which transaction receipts are to be retrieved. + * + * @returns {Promise} - Array of raw transaction receipts. + */ + private getTransactionReceipts(blockNumber: number | string): Promise { + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error(`Request timed out for block: ${blockNumber}`)); + }, 45000); + + this.sendTransactionReceiptsCall(blockNumber, timeout, resolve, reject); + }); + } + + /** + * Private method to make an RPC call through provider, to get transaction receipts for a block. + * + * @param {number} blockNumber - Block number for which receipts need to be retrieved. + * @param {NodeJS.Timeout} timeout - Timeout instance that needs to be cleared on successful query. + * @param {(value: IRawReceipt[] | PromiseLike) => void} resolve - + * The resolve callback that needs to be called on successful query. + * @param {(reason?: any) => void} reject - The reject callback that needs to be called + * on failed query. + * @param {boolean} [isRetry=false] - Boolean that is not to be set by external calls. + * Is used by internal recursive calls to identify if this request is a retry. + * + * @returns {void} + */ + private sendTransactionReceiptsCall( + blockNumber: number | string, + timeout: NodeJS.Timeout, + resolve: (value: IRawReceipt[] | PromiseLike) => void, + reject: (reason?: any) => void, + isRetry: boolean = false + ): void { + (this.eth.currentProvider as WebsocketProvider).send({ + method: "eth_getBlockReceipts", + id: Date.now().toString() + blockNumber, + params: [utils.numberToHex(blockNumber)], + jsonrpc: "2.0" + }, (error, response) => { + if (error) { + clearTimeout(timeout); + reject(error); + + return; + } + + if (!response?.result && !isRetry) { + setTimeout(() => { + this.sendTransactionReceiptsCall(blockNumber, timeout, resolve, reject, true); + }, 500); + + return; + } + + clearTimeout(timeout); + resolve(response?.result); + }); + } +} diff --git a/internal/block_getters/erigon_block_getter_worker.ts b/internal/block_getters/erigon_block_getter_worker.ts new file mode 100644 index 0000000..a245bfd --- /dev/null +++ b/internal/block_getters/erigon_block_getter_worker.ts @@ -0,0 +1,51 @@ +import { IBlockWorkerMessage } from "../interfaces/block_worker_message.js"; +import { parentPort, workerData } from "worker_threads"; +import { BlockGetter } from "./block_getter.js"; +import EthClass from "web3-eth"; + +if (!workerData || !parentPort) { + process.exit(1); +} + +const blockGetter = new BlockGetter( + //@ts-ignore + new EthClass( + //@ts-ignore + new EthClass.providers.WebsocketProvider( + workerData.endpoint, + { + reconnect: { + auto: true + }, + clientConfig: { + maxReceivedFrameSize: 1000000000, + maxReceivedMessageSize: 1000000000, + }, + timeout: 45000 + } + ) + ), + workerData.maxRetries +); + +parentPort.on("message", async (message: { + blockNumber: number, + callBackId: number +}) => { + try { + parentPort?.postMessage( + { + callBackId: message.callBackId, + error: null, + block: await blockGetter.getBlockWithTransactionReceipts(message.blockNumber) + } as IBlockWorkerMessage + ); + } catch (error) { + parentPort?.postMessage( + { + callBackId: message.callBackId, + error: error + } as IBlockWorkerMessage + ); + } +}); diff --git a/internal/block_getters/quicknode_block_getter.ts b/internal/block_getters/quicknode_block_getter.ts new file mode 100644 index 0000000..d1405d5 --- /dev/null +++ b/internal/block_getters/quicknode_block_getter.ts @@ -0,0 +1,76 @@ +import utils from "web3-utils"; +import { WebsocketProvider } from "web3-core"; +import { IQuickNodeResponse } from "../interfaces/quicknode_response.js"; +import { ITransaction } from "../interfaces/transaction.js"; +import { IBlock } from "../interfaces/block.js"; +import { IBlockGetter } from "../interfaces/block_getter.js"; +import { BlockGetter } from "./block_getter.js"; + +/** + * A wrapper class on web3 to get blocks from quicknode and format them. + * + * @author - Vibhu Rajeev + */ +export class QuickNodeBlockGetter extends BlockGetter implements IBlockGetter { + + /** + * @async + * Public method to query block data including transaction receipts of a single block. + * + * @param {number | string} blockNumber - The block number for which block data needs to be retrieved. + * + * @returns {Promise} - Block object containing all details including transaction receipts. + * + * @throws {Error} - Throws error object on failure. + */ + public async getBlockWithTransactionReceipts(blockNumber: number | string, retryCount: number = 0): Promise { + try { + const response: IQuickNodeResponse = await new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error(`Request timed out for block: ${blockNumber}`)); + }, 45000); + + (this.eth.currentProvider as WebsocketProvider).send({ + method: "qn_getBlockWithReceipts", + id: Date.now().toString() + blockNumber, + params: [ utils.numberToHex(blockNumber) ], + jsonrpc: "2.0" + }, (error, response) => { + if (error) { + clearTimeout(timeout); + reject(error); + } + + clearTimeout(timeout); + resolve(response?.result); + }); + }); + + const transactions: ITransaction[] = []; + + for (const transactionObject of response.block.transactions) { + transactions.push(this.formatRawTransactionObject( + transactionObject, + this.formatRawReceipt(response.receipts.find( + (receipt) => receipt.transactionHash === transactionObject.hash + )) ?? + await this.getTransactionReceipt(transactionObject.hash) + )); + } + + return this.formatRawBlock( + response.block, + transactions + ); + } catch (error) { + if (retryCount < this.maxRetries) { + return this.getBlockWithTransactionReceipts( + blockNumber, + retryCount + 1 + ); + } + + throw error; + } + } +} diff --git a/internal/block_getters/quicknode_block_getter_worker.ts b/internal/block_getters/quicknode_block_getter_worker.ts new file mode 100644 index 0000000..6f23612 --- /dev/null +++ b/internal/block_getters/quicknode_block_getter_worker.ts @@ -0,0 +1,51 @@ +import { IBlockWorkerMessage } from "../interfaces/block_worker_message.js"; +import { QuickNodeBlockGetter } from "./quicknode_block_getter.js"; +import { parentPort, workerData } from "worker_threads"; +import EthClass from "web3-eth"; + +if(!workerData || !parentPort) { + process.exit(1); +} + +const blockGetter = new QuickNodeBlockGetter( + //@ts-ignore + new EthClass( + //@ts-ignore + new EthClass.providers.WebsocketProvider( + workerData.endpoint, + { + reconnect: { + auto: true + }, + clientConfig: { + maxReceivedFrameSize: 1000000000, + maxReceivedMessageSize: 1000000000, + }, + timeout: 45000 + } + ) + ), + workerData.maxRetries +); + +parentPort.on("message", async (message: { + blockNumber: number, + callBackId: number +}) => { + try { + parentPort?.postMessage( + { + callBackId: message.callBackId, + error: null, + block: await blockGetter.getBlockWithTransactionReceipts(message.blockNumber) + } as IBlockWorkerMessage + ); + } catch (error) { + parentPort?.postMessage( + { + callBackId: message.callBackId, + error: error + } as IBlockWorkerMessage + ); + } +}); diff --git a/internal/block_producers/block_producer.ts b/internal/block_producers/block_producer.ts new file mode 100644 index 0000000..742db4c --- /dev/null +++ b/internal/block_producers/block_producer.ts @@ -0,0 +1,363 @@ +import { IProducedBlock, IProducedBlocksModel } from "./produced_blocks_model.js"; +import { KafkaProducerEvents, EventListener } from "../interfaces/common_kafka_events.js"; +import { AsynchronousProducer } from "../kafka/producer/asynchronous_producer.js"; +import { IBlockSubscription } from "../interfaces/block_subscription.js"; +import { BlockProducerError } from "../errors/block_producer_error.js"; +import { IProducerConfig } from "../interfaces/producer_config.js"; +import { BlockGetter } from "../block_getters/block_getter.js"; +import { Metadata, DeliveryReport } from "node-rdkafka"; +import { KafkaError } from "../errors/kafka_error.js"; +import { ICoder } from "../interfaces/coder.js"; +import { IBlock } from "../interfaces/block.js"; +import { Database } from "../mongo/database.js"; +import { Logger } from "../logger/logger.js"; +import { Queue } from "../queue/queue.js"; +import Long from "long"; + +/** + * Common lock producer class which contains the common logic to retrieve + * raw block data from the configurable "startblock" number, and produce it to + * a kafka cluster while detecting re orgs and handling them. + * The block data source, and kafka modules is provided the user of this class. + * + * @author - Vibhu Rajeev + */ +export class BlockProducer extends AsynchronousProducer { + private mongoInsertQueue: Queue; + private queueProcessingPromise?: Promise; + private mongoInsertInProcess: boolean = false; + private restartPromise?: Promise; + private producingBlockPromises: Promise[] = []; + private forceStop: boolean = false; + + /** + * @constructor + * + * @param {ICoder} coder - The protobuf coder which will be used for serialising messages. + * @param {IProducerConfig} config - Kafka producer config. + * @param {IBlockSubscription} blockSubscription - The block subscription instance which will emit block data. + * @param {BlockGetter} blockGetter - BlockGetter class instance + * @param {Database} database - database instance + * @param {IProducedBlocksModel} producedBlocksModel - The produced blocks model + * which exposes methods to add and query produced block data. + * @param {number} maxReOrgDepth - The depth upto which a re org can occur. + */ + constructor( + coder: ICoder, + config: IProducerConfig, + private blockSubscription: IBlockSubscription, + private blockGetter: BlockGetter, + private database: Database, + private producedBlocksModel: IProducedBlocksModel, + private startBlock: number = 0, + private maxReOrgDepth: number = 0 + ) { + super( + coder, + Object.assign({ + "message.max.bytes": 26214400 + }, + config + ) + ); + + this.mongoInsertQueue = new Queue(); + } + + //TODO - to rewrite the overloads and reduce the redundancy + on(event: "blockProducer.fatalError", listener: (error: KafkaError | BlockProducerError) => void): this; + on(event: "producer.error", listener: (error: KafkaError) => void): this; + on(event: "producer.disconnected", listener: () => void): this; + on(event: "delivered", listener: (report: DeliveryReport) => void): this + on(event: E, listener: EventListener): this; + on(event: Event, listener: EventListener): this { + //@ts-ignore + super.on(event, listener); + + return this; + } + + /** + * This is the main entry point for the block producer. This method is to be called externally to start indexing the raw block data from "startblock" + * + * @returns {Promise} + * + * @throws {KafkaError | BlockProducerError} - On failure to start kafka producer or block subscription. + */ + public async start(): Promise { + this.forceStop = false; + await this.database.connect(); + const metadata = await super.start(); + + this.on("delivered", async (report: DeliveryReport) => { + if (report.partition === -1) { + const error = new BlockProducerError( + "Kafka topic does not exist", + undefined, + true, + "Kafka topic does not exist or could not be created.", + "remote" + ); + + this.onError(error); + + return; + } + + Logger.info("Delivery-report:" + JSON.stringify({ + ...report.opaque, + offset: report.offset + })); + + try { + this.mongoInsertQueue.enqueue(report.opaque); + + if (!this.mongoInsertInProcess) { + this.queueProcessingPromise = this.processQueue(); + } + } catch (error) { + Logger.error(error as string | object); + } + }); + + await this.blockSubscription.subscribe( + { + next: async (block: IBlock) => { + //TODO - Simplify below logic. + const producingBlockPromise = this.produceBlock(block); + + this.producingBlockPromises.push(producingBlockPromise); + + await producingBlockPromise; + + this.producingBlockPromises = this.producingBlockPromises.filter( + (promise) => promise !== producingBlockPromise + ); + }, + error: this.onError.bind(this), + closed: () => { + Logger.info("Closed"); + } + }, + await this.getStartBlock() + ); + + return metadata; + } + + /** + * @async + * The public method to stop an indexing process. It is important to call this to avoid application crashing when + * there are connection issues. + * + * @returns {Promise} - Returns true on graceful shutdown or throws error. + * + * @throws {BlockProducerError | KafkaError} - On failure to stop block subscription or kafka producer gracefully. + */ + public async stop(): Promise { + await this.blockSubscription.unsubscribe(); + + if (this.producingBlockPromises.length) { + //Waiting for all pending blocks to be produced. + await Promise.all(this.producingBlockPromises); + } + + if (this.queueProcessingPromise) { + await this.queueProcessingPromise; + } + + await super.stop(); + + this.removeAllListeners("delivered"); + + return true; + } + + /** + * @private + * + * Private method to handle errors and logging. + * + * @param {KafkaError|BlockProducerError} error - Error object + */ + private async onError(error: KafkaError | BlockProducerError): Promise { + Logger.error(error); + + if ( + error.message === "Local: Erroneous state" || + error.message === "Erroneous state" + ) { + this.forceStop = true; + + try { + await this.stop(); + } catch { } + + this.emit( + "blockProducer.fatalError", + error + ); + + return; + } + + if (error.isFatal) { + await this.restartBlockProducer(); + } + } + + /** + * @private + * + * Private method to be used when a block producer has to be restarted. + * + * @returns {Promise} + */ + private async restartBlockProducer(): Promise { + try { + if (this.restartPromise) { + return await this.restartPromise; + } + + this.restartPromise = new Promise(async (resolve, reject) => { + try { + await this.stop(); + + if (!this.forceStop) { + await this.start(); + } + + resolve(); + } catch (error) { + reject(error); + } + }); + + await this.restartPromise; + + this.restartPromise = undefined; + } catch (error) { + this.restartPromise = undefined; + + Logger.error(error as string | object); + this.emit( + "blockProducer.fatalError", + BlockProducerError.createUnknown(error) + ); + } + } + + /** + * @private + * + * Private method to add process the queue and add the blocks in queue + * to mongo DB. + * + * @returns {Promise} + */ + private async processQueue(): Promise { + this.mongoInsertInProcess = true; + + try { + while (!this.mongoInsertQueue.isEmpty()) { + await this.addBlockToMongo( + this.mongoInsertQueue.front() as IProducedBlock + ); + this.mongoInsertQueue.shift(); + } + } catch (error) { + Logger.error(error as object); + } + + this.mongoInsertInProcess = false; + } + + /** + * @private + * + * Private method which adds given produced block details mongoDB + * + * @param {IProducedBlock} details - Produced block details to be added to mongo. + * @param {number} retryCount - param used to keep track of retry count. Should not be set externally. + * + * @returns {Promise} + */ + private async addBlockToMongo(details: IProducedBlock, retryCount: number = 0): Promise { + try { + await this.producedBlocksModel.add( + details, + this.maxReOrgDepth + ); + } catch (error) { + // Tries upto 5 times to add transaction. + if (retryCount < 4) { + return await this.addBlockToMongo(details, retryCount + 1); + } + + throw BlockProducerError.createUnknown(error); + } + } + + /** + * @async + * Internal method to retrieve last produced block from mongoDB, + * and check to see if produced blocks have been re orged when producer was offline. + * + * @returns {Promise} - Returns last produced valid block or startBlock if last block does not exist. + */ + private async getStartBlock(): Promise { + let blockNumber: number | undefined = (await this.producedBlocksModel.get())?.number; + let block: IProducedBlock | null; + + for (let depth: number = 0; depth < this.maxReOrgDepth; depth++) { + block = await this.producedBlocksModel.get(blockNumber); + if (!block) { + if (blockNumber) { + return blockNumber; + } + + return this.startBlock; + } + + const remoteBlock = await this.blockGetter.getBlock(block.number); + + if (remoteBlock.hash === block.hash) { + return (remoteBlock.number + 1); + } + + blockNumber = remoteBlock.number - 1; + } + + return blockNumber || this.startBlock; + } + + /** + * @private + * + * Private method to produce block to kafka. This method handled exceptions internally. + * + * @param {IBlock} block - Block to be produced to kafka + * + * @returns {Promise} + */ + private async produceBlock(block: IBlock): Promise { + try { + //Have to do below as toString and toNumber methods do not exist on json Long object. + const blockNumber: Long = Long.fromValue(block.number); + + await this.produceEvent( + blockNumber.toString(), + block, + undefined, + undefined, + undefined, + { + number: blockNumber.toNumber(), + hash: block.hash + } + ); + } catch (error) { + this.onError(error as KafkaError); + } + } +} diff --git a/internal/block_producers/produced_blocks_model.ts b/internal/block_producers/produced_blocks_model.ts new file mode 100644 index 0000000..2cfce7b --- /dev/null +++ b/internal/block_producers/produced_blocks_model.ts @@ -0,0 +1,47 @@ +import { Schema, Model } from "mongoose"; + +export interface IProducedBlock { + number: number + hash: string +} + +export interface IProducedBlocksModel extends Model { + get(blockNumber?: number): Promise; + add(block: T, maxReOrgDepth?: number): Promise; +} + +export const ProducedBlocksModel = new Schema>( + { + number: { + type: Number, + required: true, + unique: true + }, + hash: { + type: String, + required: true + }, + }, + { + versionKey: false, + statics: { + async get(blockNumber?: number): Promise { + const query = blockNumber ? { number: blockNumber } : {}; + + return (await this.find(query, null).sort({ number: -1 }).limit(1).exec())[0]; + }, + + async add(block: IProducedBlock, maxReOrgDepth: number = 0): Promise { + await this.create(block); + await this.deleteMany( + { + $or: [ + { number: { $lt: block.number - maxReOrgDepth } }, + { number: { $gt: block.number } } + ] + } + ); + } + } + } +); diff --git a/internal/block_subscription/abstract_block_subscription.ts b/internal/block_subscription/abstract_block_subscription.ts new file mode 100644 index 0000000..2a5f5e3 --- /dev/null +++ b/internal/block_subscription/abstract_block_subscription.ts @@ -0,0 +1,293 @@ +import { IBlockGetterWorkerPromise } from "../interfaces/block_getter_worker_promise.js"; +import { IBlockSubscription } from "../interfaces/block_subscription.js"; +import { BlockProducerError } from "../errors/block_producer_error.js"; +import { Subscription } from "web3-core-subscriptions"; +import { IObserver } from "../interfaces/observer.js"; +import { IBlock } from "../interfaces/block.js"; +import { Logger } from "../logger/logger.js"; +import { Queue } from "../queue/queue.js"; +import { Eth } from "web3-eth"; +import { Log } from "web3-core"; +import Long from "long"; + +/** + * @abstract + * + * Block subscription class which emits full block data whenever added to chain and + * takes care to backfill historical blocks requested. The backfilling strategy needs to be implemented by + * class extending from this. + * + * @author - Vibhu Rajeev + */ +export abstract class AbstractBlockSubscription extends Queue implements IBlockSubscription { + private subscription: Subscription | null = null; + // @ts-ignore + protected observer: IObserver; // ts-ignore added for this special case (it will always get initialized in the subscribe method). + private lastBlockHash: string = ""; + private processingQueue: boolean = false; + protected fatalError: boolean = false; + protected lastFinalizedBlock: number = 0; + protected nextBlock: number = 0; + protected activeBackFillingId: number | null = null; + private checkIfLiveTimeout?: NodeJS.Timeout; + private lastReceivedBlockNumber: number = 0; + private lastEmittedBlock?: { + number: number, + hash: string + }; + + /** + * @constructor + * + * @param {Eth} eth - Eth module from web3.js + * @param {number} timeout - Timeout for which if there has been no event, connection must be restarted. + */ + constructor(private eth: Eth, private timeout: number = 60000) { + super(); + } + + /** + * The subscribe method starts the subscription from last produced block, and calls observer.next for + * each new block. + * + * @param {IObserver} observer - The observer object with its functions which will be called on events. + * @param {number} startBlock - The block number to start subscribing from. + * + * @returns {Promise} + * + * @throws {BlockProducerError} - On failure to get start block or start subscription. + */ + public async subscribe(observer: IObserver, startBlock: number): Promise { + try { + //Clear any previously existing queue + this.clear(); + this.observer = observer; + this.fatalError = false; + this.lastFinalizedBlock = (await this.eth.getBlock("finalized")).number; + this.nextBlock = startBlock; + this.lastBlockHash = ""; + this.lastReceivedBlockNumber = startBlock - 1; + + // Number 50 is added to allow block producer to create log subscription even and catch up after backfilling. + if (this.lastFinalizedBlock - 50 > startBlock) { + this.backFillBlocks(); + + return; + } + + this.checkIfLive(this.lastBlockHash); + + this.subscription = this.eth.subscribe("logs", { fromBlock: this.nextBlock }) + .on("data", (log: Log) => { + try { + Logger.debug({ + location: "eth_subscribe", + blockHash: log.blockHash, + blockNumber: log.blockNumber, + logIndex: log.logIndex + }); + + if (this.lastBlockHash == log.blockHash) { + + return; + } + + //Adding below logic to get empty blocks details which have not been added to queue. + if (this.hasMissedBlocks(log.blockNumber)) { + this.enqueueMissedBlocks(log.blockNumber); + } + + this.lastBlockHash = log.blockHash; + this.lastReceivedBlockNumber = log.blockNumber; + + this.enqueue(this.getBlockFromWorker(log.blockNumber)); + + if (!this.processingQueue) { + this.processQueue(); + } + } catch (error) { + observer.error( + BlockProducerError.createUnknown(error) + ); + } + }) + .on("error", (error) => { + observer.error( + BlockProducerError.createUnknown(error) + ); + }); + } catch (error) { + throw BlockProducerError.createUnknown(error); + } + } + + /** + * Unsubscribes from block subscription and resolves on success + * + * @returns {Promise} - Resolves true on graceful unsubscription. + * + * @throws {BlockProducerError} - Throws block producer error on failure to unsubscribe gracefully. + */ + public unsubscribe(): Promise { + return new Promise((resolve, reject) => { + this.activeBackFillingId = null; + this.clear(); + clearTimeout(this.checkIfLiveTimeout); + + if (!this.subscription) { + resolve(true); + + return; + } + + (this.subscription as Subscription).unsubscribe((error: Error, success: boolean) => { + if (success) { + this.subscription = null; + resolve(true); + + return; + } + + reject(BlockProducerError.createUnknown(error)); + }); + }); + } + + /** + * Private method to emit blocks upto current finalized block. + * + * @returns {Promise} + */ + protected abstract backFillBlocks(): Promise; + + /** + * Does get the block from the defined worker (workerId). + * + * @param {number} blockNumber + * @param {number} workerId + * + * @returns {Promise} + */ + protected abstract getBlockFromWorker(blockNumber: number, workerId?: number): Promise; + + + /** + * @async + * Private method, process queued promises of getBlock, and calls observer.next when resolved. + * + * @returns {Promise} + */ + private async processQueue(): Promise { + this.processingQueue = true; + + while (!this.isEmpty() && !this.fatalError && this.observer) { + try { + const promiseResult = await (this.shift()) as IBlockGetterWorkerPromise; + + if (promiseResult?.error) { + throw promiseResult.error; + } + + const blockNumber = Long.fromValue(promiseResult.block.number); + + this.nextBlock = parseInt(blockNumber.toString()) + 1; + + //If the block number is greater than last emitted block, check if there was a re org not detected. + if ( + this.isReOrgedMissed(promiseResult.block) + ) { + throw new Error("Chain re org not handled."); + } + + this.observer.next( + promiseResult.block + ); + + this.lastEmittedBlock = { + number: blockNumber.toNumber(), + hash: promiseResult.block.hash + }; + } catch (error) { + this.fatalError = true; + this.observer.error( + BlockProducerError.createUnknown(error) + ); + + break; + } + } + + this.processingQueue = false; + } + + /** + * @private + * + * Method to check if there are empty or missed blocks between last produced block and current event received. + * + * @param {number} blockNumber - The block number of the received event log. + * + * @returns {boolean} + */ + private hasMissedBlocks(blockNumber: number): boolean { + return blockNumber - this.lastReceivedBlockNumber > 1; + } + + /** + * @private + * + * Private method to check if a re org has been missed by the subscription. + * + * @param {IBlock} block - Latest block being emitted. + * + * @returns {boolean} + */ + private isReOrgedMissed(block: IBlock): boolean { + const blockNumber = Long.fromValue(block.number); + return this.lastEmittedBlock && + blockNumber.toNumber() > this.lastEmittedBlock.number && + this.lastEmittedBlock.hash !== block.parentHash ? + true : + false; + } + + /** + * @private + * + * Method to enqueue missed or empty blocks between last produced blocks and currently received event. + * + * @param {number} currentBlockNumber - Block number for which current event was received. + * + * @returns {void} + */ + private enqueueMissedBlocks(currentBlockNumber: number): void { + for (let i = 1; i < currentBlockNumber - this.lastReceivedBlockNumber; i++) { + this.enqueue(this.getBlockFromWorker(this.lastReceivedBlockNumber + i)); + } + } + + private checkIfLive(lastBlockHash: string): void { + this.checkIfLiveTimeout = setTimeout(async () => { + //Check if the block hash has changed since the timeout. + if (this.lastBlockHash === lastBlockHash) { + try { + await this.unsubscribe(); + + await this.subscribe(this.observer, this.nextBlock); + } catch (error) { + this.observer.error( + BlockProducerError.createUnknown( + `Error when restarting producer: ${error}` + ) + ); + } + + return; + } + + this.checkIfLive(this.lastBlockHash); + }, + this.timeout + ); + } +} diff --git a/internal/block_subscription/block_polling.ts b/internal/block_subscription/block_polling.ts new file mode 100644 index 0000000..42ae452 --- /dev/null +++ b/internal/block_subscription/block_polling.ts @@ -0,0 +1,88 @@ +import { IBlockSubscription } from "../interfaces/block_subscription.js"; +import { BlockProducerError } from "../errors/block_producer_error.js"; +import { BlockGetter } from "../block_getters/block_getter.js"; +import { IObserver } from "../interfaces/observer.js"; +import { IBlock } from "../interfaces/block.js"; +import { Logger } from "../logger/logger.js"; + +/** + * A class to produce blocks based on polling + * + * @class {BlockPoller} + */ +export class BlockPoller implements IBlockSubscription { + private pollingId?: number; + + /** + * @constructor + * + * @param {BlockGetter} blockGetter - BlockGetter module from web3.js + * @param {number} blockPollingTimeout - The interval we have to poll for new blocks + */ + constructor(private blockGetter: BlockGetter, private blockPollingTimeout: number) { } + + /** + * The method to start polling for blocks from the start block to finalized block + * + * @param {IObserver} observer - The observer object with his functions + * @param {number} startBlock - Block number to start subscribing from. + * + * @returns {Promise} + */ + public async subscribe(observer: IObserver, startBlock: number): Promise { + try { + this.pollingId = Date.now(); + + //Need to separate the methods, so the subscribe method is not waiting + //indefinitely for polling to finish. + this.startBlockPolling(observer, startBlock, this.pollingId); + } catch (error) { + observer.error( + BlockProducerError.createUnknown(error) + ); + } + } + + /** + * Stops the block polling process and kills the active interval from setInterval. + * + * @returns {Promise} + */ + public async unsubscribe(): Promise { + this.pollingId = undefined; + return true; + } + + private async startBlockPolling(observer: IObserver, startBlock: number, pollingId: number): Promise { + try { + let lastBlockNumber: number = startBlock - 1; + + while (this.pollingId === pollingId) { + const latestBlockNumber = await this.blockGetter.getLatestBlockNumber(); + + Logger.debug(`Starting polling from block number ${lastBlockNumber} and latest block number is ${latestBlockNumber}`); + if (latestBlockNumber <= lastBlockNumber) { + await new Promise(r => setTimeout(r, this.blockPollingTimeout)); + } + + for (let blockNum: number = (lastBlockNumber + 1); blockNum <= latestBlockNumber && this.pollingId === pollingId; blockNum++) { + const block = await this.blockGetter.getBlockWithTransactionReceipts(blockNum); + + //Added below logic as if a new subscription is created before previous + //promise was resolved, then the block is not emitted. + if (this.pollingId !== pollingId) { + break; + } + + observer.next(block); + lastBlockNumber = blockNum; + } + } + + } catch (error) { + observer.error( + BlockProducerError.createUnknown(error) + ); + } + } +} diff --git a/internal/block_subscription/block_subscription.ts b/internal/block_subscription/block_subscription.ts new file mode 100644 index 0000000..6262385 --- /dev/null +++ b/internal/block_subscription/block_subscription.ts @@ -0,0 +1,225 @@ +import { IBlockGetterWorkerPromise } from "../interfaces/block_getter_worker_promise.js"; +import { IBlockWorkerMessage } from "../interfaces/block_worker_message.js"; +import { AbstractBlockSubscription } from "./abstract_block_subscription.js"; +import { BlockProducerError } from "../errors/block_producer_error.js"; +import { IBlock } from "../interfaces/block.js"; +import { Worker } from "worker_threads"; +import { Eth } from "web3-eth"; + +/** + * Block subscription class which emits full block data whenever added to chain. + * The subscription takes care internally to backfill if historical blocks are requested. + * + * @author - Vibhu Rajeev + */ +export class BlockSubscription extends AbstractBlockSubscription { + private workers: Worker[] = []; + + /** + * @constructor + * + * @param {Eth} eth - Eth module from web3.js + * @param {string} rpcWsEndpoints - Array of websocket urls to nodes. + * @param {number} maxRetries - Number of times to retry on failure before emitting an error. + * @param {"quicknode_block_getter" | "erigon_block_getter" | "block_getter"} blockGetterType - The type of block getter to be used for this subscription. + * @param {number} timeout - Timeout for which if there has been no event, connection must be restarted. + */ + constructor( + eth: Eth, + protected rpcWsEndpoints: string[] = [], + protected maxRetries: number = 0, + private blockGetterType: "quicknode_block_getter" | "erigon_block_getter" | "block_getter" = "block_getter", + timeout?: number + ) { + super(eth, timeout); + + this.setWorkers(); + } + + /** + * Private method to set workers as per the rpc urls passed. + * + * @returns {void} + */ + private setWorkers(): void { + const workers: Worker[] = []; + const workerPath: string = require.resolve(`../block_getters/${this.blockGetterType}_worker`); + + if (!this.rpcWsEndpoints.length) { + //TODO - throw error if no rpc + return; + } + + for (let i = 0; i < this.rpcWsEndpoints.length; i++) { + const workerData = { + endpoint: this.rpcWsEndpoints[i], + maxRetries: this.maxRetries + }; + + const worker = new Worker( + workerPath, + { + workerData + } + ); + + worker.on("exit", () => { + this.workers[i] = new Worker( + workerPath, + { + workerData + } + ); + }); + + workers.push(worker); + } + + this.workers = workers; + } + + /** + * Private method to emit blocks upto current finalized block. + * + * @returns {Promise} + */ + protected async backFillBlocks(): Promise { + try { + const backFillingId: number = Date.now(); + this.activeBackFillingId = backFillingId; + + for (let i = 0; i < this.workers.length; i++) { + this.addWorkerJobToQueue(this.nextBlock + i, i, backFillingId); + } + + while (this.nextBlock <= this.lastFinalizedBlock && !this.isEmpty()) { + const promiseResult = await this.shift(); + + if (promiseResult?.error) { + throw promiseResult.error; + } + + if (this.activeBackFillingId !== backFillingId || this.fatalError) { + return; + } + + this.observer.next( + promiseResult?.block as IBlock + ); + + this.nextBlock = this.nextBlock + 1; + } + + this.activeBackFillingId = null; + await this.subscribe(this.observer, this.nextBlock); + } catch (error) { + this.activeBackFillingId = null; + this.fatalError = true; + + if (!this.observer) { + throw BlockProducerError.createUnknown(error); + } + + this.observer.error( + BlockProducerError.createUnknown(error) + ); + } + } + + /** + * @protected + * + * Protected method that gets the block from a specific worker. + * + * @param {number} blockNumber - Block number to get the block details for + * @param {number} workerId - worker Id to which the job must be assigned. + * + * @returns {Promise} - Resolves to give formatted full block. + */ + protected getBlockFromWorker(blockNumber: number, workerId: number = 0): Promise { + return new Promise(async (resolve) => { + //Setting callback id to track callbacks replies. + const callBackId: number = Date.now() + blockNumber; + const worker = this.workers[workerId!]; + + const onMessage = function (value: IBlockWorkerMessage) { + if (value.callBackId !== callBackId) { + return; + } + + if (value.error) { + worker.removeListener("error", onError); + worker.removeListener("message", onMessage); + + return resolve({ + block: value.block, + error: value.error + }); + } + + worker.removeListener("error", onError); + worker.removeListener("message", onMessage); + + return resolve({ + block: value.block, + error: null + }); + }; + + const onError = function (error: Error) { + worker.removeListener("error", onError); + worker.removeListener("message", onMessage); + + return resolve({ + block: {} as IBlock, + error: error + }); + }; + + worker.on("message", onMessage); + worker.on("error", onError); + + worker.postMessage({ + blockNumber, + callBackId + }); + }); + } + + /** + * @private + * + * Private method to be only called by backfilling process. This method adds a block promise to queue, + * and when a worker fulfills the promise, automatically assigns it to retrieve the next block. + * + * @param {number} blockNumber - Block number to get block details for. + * @param {number} workerId - Worker to which the job must be assigned. + * @param {number} backFillingId - Backfilling Id to identify if the backfilling process is active. + * + * @returns {Promise} + */ + private async addWorkerJobToQueue(blockNumber: number, workerId: number, backFillingId: number): Promise { + const blockPromise = this.getBlockFromWorker( + blockNumber, + workerId + ); + + this.enqueue( + blockPromise + ); + + try { + await blockPromise; + } catch { + // Do nothing as is handled by queue + } + + if (backFillingId === this.activeBackFillingId && (this.nextBlock + this.getLength() < this.lastFinalizedBlock)) { + this.addWorkerJobToQueue( + this.nextBlock + this.getLength() + 1, + workerId, + backFillingId + ); + } + } +} diff --git a/internal/coder/abi_coder.ts b/internal/coder/abi_coder.ts new file mode 100644 index 0000000..f6deab5 --- /dev/null +++ b/internal/coder/abi_coder.ts @@ -0,0 +1,61 @@ +import AbiCoder from "web3-eth-abi"; + +/** + * web3 helper class to access any web3 js related functionalities, use this to define any web3 helper functions + */ +export class ABICoder { + /** + * @param type {any} - RLP type as eg address + * @param hex {string} - The bytes string given + * + * @returns {any} - Can return arrays, numbers, objects, etc. depends on the RLP type + */ + public static decodeParameter(type: any, hex: string): any { + return (AbiCoder as any).decodeParameter(type, hex); + } + + /** + * @param types {any[]} - RLP types + * @param hex {string} - The bytes string given + * + * @returns {any} - Can return an object of arrays, numbers, objects, etc. depends on the RLP type + */ + public static decodeParameters(types: any[], hex: string): { [key: string]: any } { + return (AbiCoder as any).decodeParameters(types, hex); + } + + /** + * @param types {any[]} - RLP types + * @param values {string[]} - The array of values + * + * @returns {any} - return hex string + */ + public static encodeParameters(types: any[], values: string[]): string { + return (AbiCoder as any).encodeParameters(types, values); + } + + /** + * // TODO: Overtake private type from web3.js or submit PR + * + * @param inputs {AbiInput[]} - ABI objects + * @param hex {string} - bytes given from log.data + * @param topics {string[]} - Indexed topics + * + * @returns + */ + public static decodeLog(inputs: any[], hex: string, topics: string[]): { [key: string]: string } { + return (AbiCoder as any).decodeLog(inputs, hex, topics); + } + + /** + * decode method + * + * @param {any[]} types - function name + * @param {string} data - input Data + * + * @returns {{ [key: string]: any }} + */ + public static decodeMethod(types: any[], data: string): { [key: string]: any } { + return ABICoder.decodeParameters(types, "0x" + data.slice(10)); + } +} diff --git a/internal/coder/protobuf_coder.ts b/internal/coder/protobuf_coder.ts new file mode 100644 index 0000000..ec8fd84 --- /dev/null +++ b/internal/coder/protobuf_coder.ts @@ -0,0 +1,117 @@ +import { getErrorMessage } from "../errors/get_error_message.js"; +import { CoderError } from "../errors/coder_error.js"; +import protobuf, { Root, Type } from "protobufjs"; +import { ICoder } from "../interfaces/coder.js"; +import { createRequire } from "module"; +const { load } = protobuf; + +/** + * The deserialiser class provides simple and straighforward methods to load and deserialise a buffer based on + * protobuf schemas. + * + * @author - Vibhu Rajeev + */ +export class Coder implements ICoder { + private protobufType?: Type; + private loadPromise?: Promise; + + /** + * @param {string} fileName - The file for finding the protobuf type. + * @param {string} packageName - The default package where the protobuf type is defined. + * @param {string} messageType - The default protobuf message type to be used for deserialising. + * @param {string} [fileDirectory] - Optional: The custom path for loading the protobuf type. + */ + constructor( + private fileName: string, + private packageName: string, + private messageType: string, + private fileDirectory: string = "open-api-common/schemas" + ) { } + + /** + * Public method to load the proto message type from file. + * This method must always be called before calling the deserialize or serialize method. + * + * @returns {Promise} - Returns "true" if the load was successfull. + * + * @throws {CoderError} - Throws an error if the load failed. + */ + private async loadType(): Promise { + try { + if (!this.loadPromise) { + this.loadPromise = load( + // https://nodejs.org/api/esm.html#no-requireresolve - Alternative for require.resolve + // @ts-ignore + createRequire(import.meta.url).resolve(`${this.fileDirectory}/${this.fileName}.proto`) + ).then((root: Root) => { + return root.lookupType(`${this.packageName}.${this.messageType}`); + }); + } + + return await this.loadPromise; + } catch (error) { + const message = getErrorMessage(error); + throw new CoderError( + "Coder error", + CoderError.codes.INVALID_PATH_PROTO, + true, + message + ); + } + } + + /** + * This is the main method of the class, to deserialise a given + * buffer value. If the package name and protobuf type is not passed, default values are used. + * + * @param {Buffer} buffer - Buffer to be deserialised. + * + * @returns {Promise} - Decoded object of the buffer passed. + * + * @throws {CoderError} - Throws error on failure to find protobuf type definition at the path specified. + */ + public async deserialize(buffer: Buffer): Promise { + if (! this.protobufType) { + this.protobufType = await this.loadType(); + } + + try { + return this.protobufType.decode(buffer); + } catch (error) { + throw new CoderError( + "Decoding error", + CoderError.codes.DECODING_ERROR, + true, + getErrorMessage(error) + ); + } + } + + /** + * This is the main method of the class, to deserialise a given + * buffer value. If the package name and protobuf type is not passed, default values are used. + * + * @param {object} messageObject - Message object to be serialised. + * + * @returns {Promise} - Serialised buffer of the passed object. + * + * @throws {CoderError} - Throws error object on verification failure or if failure in finding protobuf type definition. + */ + public async serialize(messageObject: object): Promise { + if (! this.protobufType) { + this.protobufType = await this.loadType(); + } + + const verificationError = this.protobufType.verify(messageObject); + if (verificationError) { + throw new CoderError( + "Message verification failed", + CoderError.codes.ENCODING_VERIFICATION_FAILED, + false, + verificationError + ); + } + + return this.protobufType.encode(messageObject).finish(); + } +} diff --git a/internal/data_transformation/abstract_data_transformer.ts b/internal/data_transformation/abstract_data_transformer.ts new file mode 100644 index 0000000..c7014ff --- /dev/null +++ b/internal/data_transformation/abstract_data_transformer.ts @@ -0,0 +1,118 @@ +import { DeserialisedMessage } from "../interfaces/deserialised_kafka_message.js"; +import { ITransformedBlock } from "../interfaces/transformed_block.js"; +import { AbstractConsumer } from "../kafka/consumer/abstract_consumer.js"; +import { AbstractProducer } from "../kafka/producer/abstract_producer.js"; +import { KafkaError } from "../errors/kafka_error.js"; +import { Logger } from "../logger/logger.js"; +import { EventEmitter } from "events"; + +/** + * Abstract DataTransformer class privides a way to create a Data transformer which takes input from the data consumer and + * produces the transformed data using the passed producer. Services need to implement their own transform method. + */ +export abstract class AbstractDataTransformer extends EventEmitter { + /** + * @param {AbstractConsumer} consumer - the consumer instance to consume raw data + * @param {AbstractProducer} producer - producer instance to produce the transformed data + */ + constructor( + protected consumer: AbstractConsumer, + protected producer: AbstractProducer, + protected restart: boolean = true + ) { + super(); + } + + /** + * @param {T} data can be of any type of raw block + * + * @returns {Promise>} - Returns the transformed data of type G + */ + protected abstract transform(data: T): Promise>; + + /** + * This method starts the data transformation process by inititating the consumer and calling the onData function + * + * @returns {Promise} + */ + public async start(): Promise { + Logger.info("Starting transformer."); + await this.producer.start(); + + return await this.consumer.start({ + next: this.onData.bind(this), + error: (error) => { + Logger.error(error); + }, + closed: async () => { + if (this.restart) { + try { + await this.producer.stop(); + + await this.start(); + + return; + } catch (error) { + return this.emit( + "dataTransformer.fatalError", + KafkaError.createUnknown(error) + ); + } + } + + this.emit( + "dataTransformer.fatalError", + new KafkaError( + "Transformer stopped", + KafkaError.codes.UNKNOWN_CONSUMER_ERR, + true, + "Transformer stopped due to a fatal error." + ) + ); + + return; + } + }); + } + + public on(event: "dataTransformer.fatalError", listener: (error: KafkaError) => void): this { + super.on(event, listener); + + return this; + } + + /** + * Will be called on each in coming event and transform the message value as expected to type T. + * + * @param {DeserialisedMessage} message + * + * @returns {Promise} + */ + protected async onData(message: DeserialisedMessage): Promise { + const transformedBlock = await this.transform(message.value as T); + + Logger.debug({ + location: "abstract_data_transformer", + function: "onData", + status: "data received", + data: { + blockNumber: transformedBlock.blockNumber, + length: transformedBlock.data.length + } + }); + + if (transformedBlock.data.length > 0) { + await this.producer.produceEvent(transformedBlock.blockNumber.toString(), transformedBlock); + + Logger.info({ + location: "abstract_data_transformer", + function: "onData", + status: "data produced", + data: { + blockNumber: transformedBlock.blockNumber, + length: transformedBlock.data.length + } + }); + } + } +} diff --git a/internal/enums/bridgetype.ts b/internal/enums/bridgetype.ts new file mode 100644 index 0000000..d909768 --- /dev/null +++ b/internal/enums/bridgetype.ts @@ -0,0 +1,8 @@ +/** + * Enum for BridgeType. It contains the 3 values PLASMA, POS, FX +*/ +export enum BridgeType { + PLASMA = "PLASMA", + POS = "POS", + FX = "FX" +} diff --git a/internal/enums/tokentype.ts b/internal/enums/tokentype.ts new file mode 100644 index 0000000..bb0090b --- /dev/null +++ b/internal/enums/tokentype.ts @@ -0,0 +1,11 @@ +/** + * Enum for TokenType. It contains the 4 values ERC20, ERC721, ERC1155 and ETHER +*/ +export enum TokenType { + ERC20 = "ERC20", + ERC721 = "ERC721", + ERC1155 = "ERC1155", + ETHER = "ETHER", + NONE = "NONE" +} + diff --git a/internal/errors/api_error.ts b/internal/errors/api_error.ts new file mode 100644 index 0000000..7760713 --- /dev/null +++ b/internal/errors/api_error.ts @@ -0,0 +1,57 @@ +import { createErrorObject } from "./create_error_object.js"; +import { isBaseError } from "./is_base_error.js"; +import { BaseError } from "./base_error.js"; +import { codes } from "./error_codes.js"; + +/** + * BlockProducerError object used within common. + */ +export class ApiError extends BaseError { + public static codes = { + ...BaseError.codes, + ...codes.api + }; + + /** + * @param name {string} - The error name + * @param code {number} - The error code + * @param isFatal {boolean} - Flag to know if it is a fatal error + * @param message {string} - The actual error message + * @param origin {string} - The point this error originated + * @param stack {string} - The stack trace + */ + constructor( + name: string = "Internal server error", + code: number = ApiError.codes.SERVER_ERROR, + isFatal: boolean = false, + message?: string, + origin: string = "local", + stack?: string, + ) { + super(name, code, isFatal, message, origin, stack); + } + + /** + * Static method that converts any error that is not an instance of BaseError into BlockProducerError + * + * @param {any} error - Error that needs to be checked and converted. + * + * @returns {BlockProducerError|BaseError} - Returns either BlockProducer or any instance of BaseError + */ + public static createUnknown(error: any, isLocal: boolean = true): ApiError | BaseError { + if (!isBaseError(error)) { + const errorObject = createErrorObject(error); + + return new ApiError( + "Internal server error", + ApiError.codes.SERVER_ERROR, + true, + errorObject.message, + isLocal ? "local" : "remote", + errorObject.stack + ); + } + + return error; + } +} diff --git a/internal/errors/base_error.ts b/internal/errors/base_error.ts new file mode 100644 index 0000000..f70cb0e --- /dev/null +++ b/internal/errors/base_error.ts @@ -0,0 +1,32 @@ +import { codes } from "./error_codes.js"; + +/** + * BaseError used within the micro services that guarantees we don't loose the stack trace. + */ +export class BaseError extends Error { + /** + * @param name {string} - The error name + * @param code {number} - The error code + * @param isFatal {boolean} - Flag to know if it is a fatal error + * @param message {string} - The actual error message + * @param origin {string} - The point this error originated + * @param stack {string} - The stack trace + */ + constructor( + public name: string, + public code: number, + public isFatal: boolean = false, + message?: string, + public origin?: string, + public stack?: string, + ) { + super(message || name); + + if (stack) { + this.stack = stack; + } + } + + public static codes = codes.base; + public identifier: number = BaseError.codes.BASE_ERROR; +} diff --git a/internal/errors/block_producer_error.ts b/internal/errors/block_producer_error.ts new file mode 100644 index 0000000..70b67c9 --- /dev/null +++ b/internal/errors/block_producer_error.ts @@ -0,0 +1,57 @@ +import { createErrorObject } from "./create_error_object.js"; +import { isBaseError } from "./is_base_error.js"; +import { BaseError } from "./base_error.js"; +import { codes } from "./error_codes.js"; + +/** + * BlockProducerError object used within common. + */ +export class BlockProducerError extends BaseError { + /** + * @param name {string} - The error name + * @param code {number} - The error code + * @param isFatal {boolean} - Flag to know if it is a fatal error + * @param message {string} - The actual error message + * @param origin {string} - The point this error originated + * @param stack {string} - The stack trace + */ + constructor( + name: string = "Block producer error", + code: number = BlockProducerError.codes.UNKNOWN_ERR, + isFatal: boolean = false, + message?: string, + origin: string = "local", + stack?: string, + ) { + super(name, code, isFatal, message, origin, stack); + } + + public static codes = { + ...BaseError.codes, + ...codes.blockProducer + }; + + /** + * Static method that converts any error that is not an instance of BaseError into BlockProducerError + * + * @param {any} error - Error that needs to be checked and converted. + * + * @returns {BlockProducerError|BaseError} - Returns either BlockProducer or any instance of BaseError + */ + public static createUnknown(error: any, isLocal: boolean = true): BlockProducerError | BaseError { + if (!isBaseError(error)) { + const errorObject = createErrorObject(error); + + return new BlockProducerError( + "Block producer error", + BlockProducerError.codes.UNKNOWN_ERR, + true, + errorObject.message, + isLocal ? "local" : "remote", + errorObject.stack + ); + } + + return error; + } +} diff --git a/internal/errors/coder_error.ts b/internal/errors/coder_error.ts new file mode 100644 index 0000000..724ccf3 --- /dev/null +++ b/internal/errors/coder_error.ts @@ -0,0 +1,29 @@ +import { BaseError } from "./base_error.js"; +import { codes } from "./error_codes.js"; + +/** + * Error type specific to coder errors + */ +export class CoderError extends BaseError { + public static codes = { + ...BaseError.codes, + ...codes.coder + }; + + /** + * @param name {string} - The error name + * @param code {number} - The error code + * @param isFatal {boolean} - Flag to know if it is a fatal error + * @param message {string} - The actual error message + * @param stack {string} - The stack trace + */ + constructor( + name: string = "Coder Error", + code: number = CoderError.codes.UNKNOWN_CODER_ERR, + isFatal: boolean = false, + message?: string, + stack?: string + ) { + super(name, code, isFatal, message, "local", stack); + } +} \ No newline at end of file diff --git a/internal/errors/create_error_object.ts b/internal/errors/create_error_object.ts new file mode 100644 index 0000000..cb13bd2 --- /dev/null +++ b/internal/errors/create_error_object.ts @@ -0,0 +1,14 @@ +/** + * Small helper we have added for now. + * + * @param error {unknown} + * + * @returns {Error|TypeError} + */ +export function createErrorObject(error: unknown): Error|TypeError { + if (error instanceof Error || error instanceof TypeError) { + return error; + } + + return new Error(String(error)); +} diff --git a/internal/errors/error_codes.ts b/internal/errors/error_codes.ts new file mode 100644 index 0000000..9e51edd --- /dev/null +++ b/internal/errors/error_codes.ts @@ -0,0 +1,45 @@ +export const codes = { + // Base error identifier + base: { BASE_ERROR: 100 }, + + // Coder related errors. + coder: { + UNKNOWN_CODER_ERR: 1000, + INVALID_PATH_PROTO: 1001, + INVALID_PATH_TYPE: 1002, + DECODING_ERROR: 1003, + ENCODING_VERIFICATION_FAILED: 1004 + }, + + // Kafka Consumer error codes. + kafkaclient: { + UNKNOWN_CONSUMER_ERR: 2000, + CONSUMER_OBSERVER_INVALID: 2001, + INVALID_CODER_CONFIG: 2002, + UNKNOWN_PRODUCER_ERR: 3000, + DELIVERY_TIMED_OUT: 3001 + }, + + // Block producer error codes. + blockProducer: { + UNKNOWN_ERR: 4000, + RECEIPT_NOT_FOUND: 4001, + OBSERVER_NOT_SET: 4002 + }, + + // Event consumer error codes + eventConsumer: { + UNKNOWN_ERR: 5000, + SAVE_EXECUTE_ERROR: 5001, + MAPPING_ERROR: 5002, + COMMAND_EXECUTE_ERROR: 5003, + INVALID_PARAMS_VALIDATION: 5004 + }, + + // API Errors + api: { + BAD_REQUEST: 400, + NOT_FOUND: 404, + SERVER_ERROR: 500 + } +}; diff --git a/internal/errors/event_consumer_error.ts b/internal/errors/event_consumer_error.ts new file mode 100644 index 0000000..1faa5b3 --- /dev/null +++ b/internal/errors/event_consumer_error.ts @@ -0,0 +1,57 @@ +import { createErrorObject } from "./create_error_object.js"; +import { isBaseError } from "./is_base_error.js"; +import { BaseError } from "./base_error.js"; +import { codes } from "./error_codes.js"; + +/** + * Error type specific to event consumer errors + */ +export class EventConsumerError extends BaseError { + public static codes = { + ...BaseError.codes, + ...codes.eventConsumer + }; + + /** + * @param name {string} - The error name + * @param code {number} - The error code + * @param isFatal {boolean} - Flag to know if it is a fatal error + * @param message {string} - The actual error message + * @param origin {string} - The point this error originated + * @param stack {string} - The stack trace + */ + constructor( + name: string = "Event Consumer Error", + code: number = EventConsumerError.codes.UNKNOWN_ERR, + isFatal: boolean = false, + message?: string, + origin: string = "local", + stack?: string + ) { + super(name, code, isFatal, message, origin, stack); + } + + /** + * Static method that converts any error that is not an instance of BaseError into BlockProducerError + * + * @param {any} error - Error that needs to be checked and converted. + * + * @returns {BlockProducerError|BaseError} - Returns either BlockProducer or any instance of BaseError + */ + public static createUnknown(error: any, isLocal: boolean = true): EventConsumerError | BaseError { + if (!isBaseError(error)) { + const errorObject = createErrorObject(error); + + return new EventConsumerError( + "Event Consumer Error", + EventConsumerError.codes.UNKNOWN_ERR, + true, + errorObject.message, + isLocal ? "local" : "remote", + errorObject.stack + ); + } + + return error; + } +} diff --git a/internal/errors/get_error_message.ts b/internal/errors/get_error_message.ts new file mode 100644 index 0000000..b4c12b0 --- /dev/null +++ b/internal/errors/get_error_message.ts @@ -0,0 +1,15 @@ +/** + * Smaller helper we have added for now. + * + * @param error {unkown} + * + * @returns {String} + */ +export function getErrorMessage(error: unknown): string { + if (!error) { + return "Unknown error"; + } + + if (error instanceof Error) return error.message; + return typeof error === "object" ? JSON.stringify(error) : String(error); +} diff --git a/internal/errors/is_base_error.ts b/internal/errors/is_base_error.ts new file mode 100644 index 0000000..1e1af62 --- /dev/null +++ b/internal/errors/is_base_error.ts @@ -0,0 +1,15 @@ +import { BaseError } from "./base_error.js"; + +/** + * Check if the given error is BaseError. Small helper we might will remove later on. + * + * @param error {unknown} + * + * @returns {boolean} + */ +export function isBaseError(error: unknown): boolean { + return ( + //@ts-ignore + typeof error === "object" && error !== null && "identifier" in error && error.identifier === BaseError.codes.BASE_ERROR + ); +} diff --git a/internal/errors/is_librdkafka_error.ts b/internal/errors/is_librdkafka_error.ts new file mode 100644 index 0000000..c62c6aa --- /dev/null +++ b/internal/errors/is_librdkafka_error.ts @@ -0,0 +1,20 @@ +import { LibrdKafkaError } from "node-rdkafka"; + +/** + * Checks if given error is a LibrdKafkaError. Small helper we might will remove later on. + * + * @param error {unknown} + * + * @returns {boolean} + */ +export function isLibrdKafkaError(error: unknown): boolean { + return ( + typeof error === "object" && + error !== null && + "message" in error && + "code" in error && + "isFatal" in error && + "origin" in error && + "stack" in error + ); +} diff --git a/internal/errors/kafka_error.ts b/internal/errors/kafka_error.ts new file mode 100644 index 0000000..257ab23 --- /dev/null +++ b/internal/errors/kafka_error.ts @@ -0,0 +1,80 @@ +import { isLibrdKafkaError } from "./is_librdkafka_error.js"; +import { createErrorObject } from "./create_error_object.js"; +import { isBaseError } from "./is_base_error.js"; +import { LibrdKafkaError } from "node-rdkafka"; +import { BaseError } from "./base_error.js"; +import { codes } from "./error_codes.js"; + +/** + * KafkaError object used within common. + */ +export class KafkaError extends BaseError { + /** + * @param name {string} - The error name + * @param code {number} - The error code + * @param isFatal {boolean} - Flag to know if it is a fatal error + * @param message {string} - The actual error message + * @param origin {string} - The point this error originated + * @param stack {string} - The stack trace + */ + constructor( + name: string = "Kafka Error", + code: number, + isFatal: boolean = false, + message?: string, + origin: string = "local", + stack?: string, + ) { + super(name, code, isFatal, message, origin, stack); + } + + public static codes = { + ...BaseError.codes, + ...codes.kafkaclient + }; + + /** + * Internal method to convert LibKafkaError to KafkaError + * + * @param {LibrdKafkaError} error - The error object to be converted. + * + * @returns {KafkaError} - Returns the kafka error created from the error passed. + */ + public static convertLibError(error: LibrdKafkaError, isProducer: boolean = false): KafkaError { + return new KafkaError( + isProducer ? "Kafka producer error" : "Kafka consumer error", + error.code || (isProducer ? KafkaError.codes.UNKNOWN_PRODUCER_ERR : KafkaError.codes.UNKNOWN_CONSUMER_ERR), + error.isFatal, + error.message, + error.origin, + error.stack + ); + } + + /** + * Static method that converts any error that is not an instance of BaseError into KafkaError + * + * @param {any} error - Error that needs to be checked and converted. + * + * @returns {KafkaError|BaseError} - Returns either KafkaError or any instance of BaseError + */ + public static createUnknown(error: any, isProducer: boolean = false): KafkaError | BaseError { + if (!isBaseError(error)) { + if (isLibrdKafkaError(error)) { + return KafkaError.convertLibError(error, isProducer); + } + + const errorObject = createErrorObject(error); + return new KafkaError( + isProducer ? "Kafka producer error" : "Kafka consumer error", + isProducer ? KafkaError.codes.UNKNOWN_PRODUCER_ERR : KafkaError.codes.UNKNOWN_CONSUMER_ERR, + true, + errorObject.message, + "local", + errorObject.stack + ); + } + + return error as KafkaError | BaseError; + } +} diff --git a/internal/event_consumer/abstract_event_consumer.ts b/internal/event_consumer/abstract_event_consumer.ts new file mode 100644 index 0000000..711f001 --- /dev/null +++ b/internal/event_consumer/abstract_event_consumer.ts @@ -0,0 +1,44 @@ +import { DeserialisedMessage } from "../interfaces/deserialised_kafka_message.js"; +import { SynchronousConsumer } from "../kafka/consumer/synchronous_consumer.js"; +import { EventConsumerError } from "../errors/event_consumer_error.js"; +import { Logger } from "../logger/logger.js"; + +/** + * This class will start consuming the events and has functions to call what to do with the data for each event. + */ +export abstract class AbstractEventConsumer extends SynchronousConsumer { + /** + * Public execute function has no parameters. this function will start consuming the events and will call + * the callback function when an event is consumed. only need to call this event when you want to start + * consuming the event. + * + * @returns {Promise} + */ + public async execute(): Promise { + await this.start({ + next: async (event) => { + try { + await this.onEvent(event); + } catch (error) { + throw EventConsumerError.createUnknown(error); + } + }, + error: (err: Error) => { + Logger.error(err); + }, + closed: () => { + Logger.info(`Consumer stopped for topics ${this.topics}`); + }, + }); + } + + /** + * Private internal callback method for the consumer to call when any deposit data is received. this function will + * filter data based on its token type and execute the command based on which tokentype is present. + * + * @param {DeserialisedMessage} data - Data that is received from kafka consumer + * + * @returns {Promise} + */ + protected abstract onEvent(data: DeserialisedMessage): Promise; +} diff --git a/internal/filter/bloom_filter.ts b/internal/filter/bloom_filter.ts new file mode 100644 index 0000000..2ee7589 --- /dev/null +++ b/internal/filter/bloom_filter.ts @@ -0,0 +1,26 @@ +import { isContractAddressInBloom, isTopicInBloom } from "ethereum-bloom-filters"; + +/** + * Bloomfilter class which extends the Bloom filter package, all methods to be implemented here. + */ +export class BloomFilter { + /** + * @param {string} bloom - The bloom filter passed + * @param {string} contractAddress - The address you are looking for + * + * @returns {boolean} + */ + public static isContractAddressInBloom(bloom: string, contractAddress: string): boolean { + return isContractAddressInBloom(bloom, contractAddress); + } + + /** + * @param {string} bloom - The bloom filter passed + * @param {string} topic - The topic signature you are looking for + * + * @returns {boolean} + */ + public static isTopicInBloom(bloom: string, topic: string): boolean { + return isTopicInBloom(bloom, topic); + } +} \ No newline at end of file diff --git a/internal/formatters/block_formatter.ts b/internal/formatters/block_formatter.ts new file mode 100644 index 0000000..81d1863 --- /dev/null +++ b/internal/formatters/block_formatter.ts @@ -0,0 +1,210 @@ +import { ITransactionReceipt } from "../interfaces/transaction_receipt.js"; +import { TransactionReceipt } from "web3-core"; +import { ITransaction } from "../interfaces/transaction.js"; +import { BlockTransactionObject } from "web3-eth"; +import { formatters } from "web3-core-helpers"; +import { IBlock } from "../interfaces/block.js"; +import Long from "long"; +import { IRawBlock } from "../interfaces/raw_block.js"; +import { IRawTransaction } from "../interfaces/raw_transaction.js"; +import { IRawReceipt } from "../interfaces/raw_receipt.js"; +import { IWeb3Transaction } from "../interfaces/web3_transaction.js"; +import { IWeb3TransactionReceipt } from "../interfaces/web3_transaction_receipt.js"; +import utils from "web3-utils"; + + +export class BlockFormatter { + /** + * @protected + * + * Formats a raw transaction receipt response from a JSON RPC request to EVM Client. + * + * @param {IRawReceipt} receipt - The transaction receipt to format. + * + * @returns { ITransactionReceipt | void } - The formatted transaction receipt object. + */ + protected formatRawReceipt(receipt?: IRawReceipt): ITransactionReceipt | void { + if (!receipt) { + return; + } + + if (typeof receipt !== "object") { + throw new Error("Received receipt is invalid: " + receipt); + } + + return this.formatTransactionReceipt({ + ...receipt, + blockNumber: utils.hexToNumber(receipt.transactionIndex) as number, + cumulativeGasUsed: utils.hexToNumber(receipt.cumulativeGasUsed) as number, + transactionIndex: utils.hexToNumber(receipt.transactionIndex) as number, + gasUsed: utils.hexToNumber(receipt.gasUsed) as number, + logs: receipt.logs?.length ? receipt.logs.map(log => formatters.outputLogFormatter(log)) : [], + effectiveGasPrice: receipt.effectiveGasPrice, + status: typeof receipt.status !== "undefined" && receipt.status !== null ? + Boolean(parseInt(receipt.status)) : false + }); + } + + /** + * @protected + * + * Formats a raw transaction object returned by an evm client. + * + * @param {IRawTransaction} transaction - The transaction object to format. + * @param {ITransactionReceipt} receipt - Formatted transaction receipt object to be + * added to transaction object. + * + * @returns {ITransaction} - The formatted transaction object. + */ + protected formatRawTransactionObject(transaction: IRawTransaction, receipt: ITransactionReceipt): ITransaction { + return this.formatTransactionObject( + formatters.outputTransactionFormatter(transaction), + receipt + ); + } + + /** + * @protected + * + * Formats a raw block response returned by a JSON RPC request to evm client. + * + * @param {IRawBlock} block - The block object to be formatted. + * @param {[ITransaction]} transactions - Formatted transactions array that needs to be added + * to the formatted block object. + * + * @returns {IBlock} - Formatted block object with transactions and transaction receipts. + */ + protected formatRawBlock(block: IRawBlock, transactions: ITransaction[]): IBlock { + return this.formatBlockWithTransactions( + formatters.outputBlockFormatter(block), + transactions + ); + } + + /** + * @protected + * + * Formats a block object that is returned by 'web3.js'. + * + * @param {BlockTransactionObject} block - The block object to be formatted returned by 'web3.js'. + * @param {[ITransaction]} transactions - Formatted transactions array that needs to be added + * to the formatted block object. + * + * @returns {IBlock} - Formatted block object with transactions and transaction receipts. + */ + protected formatBlockWithTransactions(block: BlockTransactionObject, transactions: ITransaction[]): IBlock { + return { + ...block, + nonce: Long.fromValue( + utils.hexToNumberString( + block.nonce + ), + true + ), + difficulty: utils.toHex(block.difficulty), + totalDifficulty: utils.toHex(block.totalDifficulty), + timestamp: Long.fromValue((block.timestamp as number) * 1000, true), + number: Long.fromValue(block.number, true), + baseFeePerGas: (block.baseFeePerGas || block.baseFeePerGas === 0 ? + utils.toHex(block.baseFeePerGas) : + undefined + ), + size: utils.toHex(block.size), + transactions: transactions, + gasLimit: Long.fromValue(block.gasLimit, true), + gasUsed: Long.fromValue(block.gasUsed, true), + }; + } + + /** + * @protected + * + * Formats a raw transaction object that is returned by the 'web3.js' formatter. + * + * @param {IWeb3Transaction} transactionObject - The transaction object to format. + * @param {ITransactionReceipt} receipt - Formatted transaction receipt object to be + * added to transaction object. + * + * @returns {ITransaction} - The formatted transaction object. + */ + protected formatTransactionObject(transactionObject: IWeb3Transaction, receipt: ITransactionReceipt): ITransaction { + return { + ...transactionObject, + receipt, + value: utils.toHex(transactionObject.value), + transactionIndex: ( + transactionObject.transactionIndex || transactionObject.transactionIndex === 0 ? + Long.fromValue(transactionObject.transactionIndex, true) : + null + ), + gas: Long.fromValue(transactionObject.gas, true), + gasPrice: utils.toHex(transactionObject.gasPrice), + nonce: Long.fromValue(transactionObject.nonce, true), + maxFeePerGas: ( + transactionObject.maxFeePerGas || transactionObject.maxFeePerGas === 0 ? + utils.toHex( + transactionObject.maxFeePerGas + ) : + undefined + ), + maxPriorityFeePerGas: ( + transactionObject.maxPriorityFeePerGas || transactionObject.maxPriorityFeePerGas === 0 ? + utils.toHex( + transactionObject.maxPriorityFeePerGas + ) : + undefined + ), + blockNumber: ( + transactionObject.blockNumber || transactionObject.blockNumber === 0 ? + Long.fromValue(transactionObject.blockNumber, true) : + null + ) + }; + } + + /** + * @protected + * + * Formats transaction receipt object returned or formatted by 'web3.js'. + * + * @param {IRawReceipt} transactionReceipt - The transaction receipt to format. + * + * @returns { ITransactionReceipt | void } - The formatted transaction receipt object. + */ + protected formatTransactionReceipt(transactionReceipt: IWeb3TransactionReceipt): ITransactionReceipt { + return { + ...transactionReceipt, + effectiveGasPrice: ( + transactionReceipt.effectiveGasPrice || transactionReceipt.effectiveGasPrice === 0 ? + utils.toHex( + transactionReceipt.effectiveGasPrice + ) : + undefined + ), + cumulativeGasUsed: Long.fromValue( + transactionReceipt.cumulativeGasUsed, + true + ), + transactionIndex: Long.fromValue( + transactionReceipt.transactionIndex, + true + ), + blockNumber: Long.fromValue( + transactionReceipt.blockNumber, + true + ), + gasUsed: Long.fromValue( + transactionReceipt.gasUsed, + true + ), + logs: transactionReceipt.logs.map((log) => { + return { + ...log, + transactionIndex: Long.fromValue(log.transactionIndex, true), + logIndex: Long.fromValue(log.logIndex, true), + blockNumber: Long.fromValue(log.blockNumber, true) + }; + }) + }; + } +} diff --git a/internal/interfaces/async_observer.ts b/internal/interfaces/async_observer.ts new file mode 100644 index 0000000..c33bed2 --- /dev/null +++ b/internal/interfaces/async_observer.ts @@ -0,0 +1,7 @@ +import { Observer } from "rxjs"; + +export interface AsyncObserver extends Observer { + next(): Promise + error(error: unknown): void + complete(): void +} diff --git a/internal/interfaces/block.ts b/internal/interfaces/block.ts new file mode 100644 index 0000000..62156fb --- /dev/null +++ b/internal/interfaces/block.ts @@ -0,0 +1,25 @@ +import { ITransaction } from "./transaction.js"; +import Long from "long"; + +export interface IBlock { + difficulty?: string; + totalDifficulty?: string; + number: Long; + gasLimit: Long; + baseFeePerGas?: string; + gasUsed: Long; + logsBloom: string; + hash: string; + parentHash: string; + receiptsRoot: string; + sha3Uncles: string; + size: string; + stateRoot: string; + timestamp: Long; + transactionsRoot: string; + miner: string; + nonce: Long; + extraData: string; + transactions: ITransaction[]; + //TODO - store uncles. +} diff --git a/internal/interfaces/block_getter.ts b/internal/interfaces/block_getter.ts new file mode 100644 index 0000000..26dabe8 --- /dev/null +++ b/internal/interfaces/block_getter.ts @@ -0,0 +1,8 @@ +import { Block } from "web3-eth"; +import { IBlock } from "./block.js"; + +export interface IBlockGetter { + getBlock(blockNumber: number|string): Promise; + getBlockWithTransactionReceipts(blockNumber: number): Promise; + getLatestBlockNumber(): Promise; +} diff --git a/internal/interfaces/block_getter_worker_promise.ts b/internal/interfaces/block_getter_worker_promise.ts new file mode 100644 index 0000000..e0d2f02 --- /dev/null +++ b/internal/interfaces/block_getter_worker_promise.ts @@ -0,0 +1,5 @@ +import { IBlock } from "./block.js"; + +export interface IBlockGetterWorkerPromise { + block: IBlock, error: Error | null +} diff --git a/internal/interfaces/block_header.ts b/internal/interfaces/block_header.ts new file mode 100644 index 0000000..0816283 --- /dev/null +++ b/internal/interfaces/block_header.ts @@ -0,0 +1,16 @@ +export interface IBlockHeader { + number: number; + hash: string; + gasLimit: number; + gasUsed: number; + logsBloom: string; + parentHash: string; + receiptsRoot: string; + sha3Uncles: string; + stateRoot: string; + timestamp: number|string; + transactionsRoot: string; + miner: string; + nonce: string; + extraData?: string; +} diff --git a/internal/interfaces/block_producer_config.ts b/internal/interfaces/block_producer_config.ts new file mode 100644 index 0000000..36ed66c --- /dev/null +++ b/internal/interfaces/block_producer_config.ts @@ -0,0 +1,12 @@ +import { IProducerConfig } from "./producer_config.js"; + +export interface IBlockProducerConfig extends IProducerConfig { + startBlock?: number, + rpcWsEndpoints?: string[], + mongoUrl?: string, + maxReOrgDepth?: number, + maxRetries?: number, + blockPollingTimeout?: number, + blockSubscriptionTimeout?: number, + type?: string +} diff --git a/internal/interfaces/block_subscription.ts b/internal/interfaces/block_subscription.ts new file mode 100644 index 0000000..8cd4663 --- /dev/null +++ b/internal/interfaces/block_subscription.ts @@ -0,0 +1,6 @@ +import { IObserver } from "./observer.js"; + +export interface IBlockSubscription { + subscribe(observer: IObserver, startBlock: number): Promise | void, + unsubscribe(): Promise +} diff --git a/internal/interfaces/block_worker_message.ts b/internal/interfaces/block_worker_message.ts new file mode 100644 index 0000000..3e73906 --- /dev/null +++ b/internal/interfaces/block_worker_message.ts @@ -0,0 +1,7 @@ +import { IBlock } from "./block.js"; + +export interface IBlockWorkerMessage { + callBackId: number; + error: null | Error; + block: IBlock +} diff --git a/internal/interfaces/coder.ts b/internal/interfaces/coder.ts new file mode 100644 index 0000000..60e6830 --- /dev/null +++ b/internal/interfaces/coder.ts @@ -0,0 +1,12 @@ +export interface ICoder { + deserialize: ( + buffer: Buffer, + messageType?: string, + packageName?: string + ) => Promise, + serialize: ( + messageObject: object, + messageType?: string, + packageName?: string + ) => Promise +} diff --git a/internal/interfaces/coder_config.ts b/internal/interfaces/coder_config.ts new file mode 100644 index 0000000..bf63526 --- /dev/null +++ b/internal/interfaces/coder_config.ts @@ -0,0 +1,7 @@ + +export interface ICoderConfig { + fileName: string, + packageName: string, + messageType: string, + fileDirectory?: string +} diff --git a/internal/interfaces/common_kafka_events.ts b/internal/interfaces/common_kafka_events.ts new file mode 100644 index 0000000..1affe30 --- /dev/null +++ b/internal/interfaces/common_kafka_events.ts @@ -0,0 +1,36 @@ +import { ClientMetrics, LibrdKafkaError, DeliveryReport, ReadyInfo, Metadata, Message, EofEvent, TopicPartition, SubscribeTopicList, TopicPartitionOffset } from "node-rdkafka"; +// +type KafkaClientEvents = "disconnected" | "ready" | "connection.failure" | "event.error" | "event.stats" | "event.log" | "event.event" | "event.throttle"; + +type EventListenerMap = { + // ### Client + // connectivity events + "disconnected": (metrics: ClientMetrics) => void, + "ready": (info: ReadyInfo, metadata: Metadata) => void, + "connection.failure": (error: LibrdKafkaError, metrics: ClientMetrics) => void, + // event messages + "event.error": (error: LibrdKafkaError) => void, + "event.stats": (eventData: any) => void, + "event.log": (eventData: any) => void, + "event.event": (eventData: any) => void, + "event.throttle": (eventData: any) => void, + // ### Consumer only + // domain events + "data": (arg: Message) => void, + "partition.eof": (arg: EofEvent) => void, + "rebalance": (err: LibrdKafkaError, assignments: TopicPartition[]) => void, + "rebalance.error": (err: Error) => void, + // connectivity events + "subscribed": (topics: SubscribeTopicList) => void, + "unsubscribe": () => void, + "unsubscribed": () => void, + // offsets + "offset.commit": (error: LibrdKafkaError, topicPartitions: TopicPartitionOffset[]) => void, + // ### Producer only + // delivery + "delivery-report": (error: LibrdKafkaError, report: DeliveryReport) => void, +} + +export type KafkaConsumerEvents = "data" | "partition.eof" | "rebalance" | "rebalance.error" | "subscribed" | "unsubscribed" | "unsubscribe" | "offset.commit" | KafkaClientEvents; +export type KafkaProducerEvents = "delivery-report" | KafkaClientEvents; +export type EventListener = K extends keyof EventListenerMap ? EventListenerMap[K] : never; diff --git a/internal/interfaces/config.ts b/internal/interfaces/config.ts new file mode 100644 index 0000000..b60146c --- /dev/null +++ b/internal/interfaces/config.ts @@ -0,0 +1,79 @@ +export interface IConfig { + [key: string]: string, + + POS_DEPOSIT_TO_ADDRESS: string, + FX_ROOT_TUNNEL: string, + PLASMA_DEPOSIT_TO_ADDRESS: string, + POS_ERC20_PREDICATE_PROXY: string, + POS_ERC721_PREDICATE_PROXY: string, + POS_ERC1155_PREDICATE_PROXY: string, + POS_ERC20_MINTABLE_PREDICATE_PROXY: string, + POS_ERC721_MINTABLE_PREDICATE_PROXY: string, + POS_ERC1155_MINTABLE_PREDICATE_PROXY: string, + POS_ETHER_PREDICATE_PROXY: string, + POS_ROOT_CHAIN_MANAGER_PROXY: string, + STATE_SENDER: string, + STATE_RECEIVER: string, + GOVERNANCE_PROXY: string, + ROOT_CHAIN_PROXY: string, + + LOCKED_ERC20_TOPIC: string, + LOCKED_ERC721_TOPIC: string, + LOCKED_ERC1155_TOPIC: string, + LOCKED_ETHER_TOPIC: string, + LOCKED_ERC20_MINTABLE_TOPIC: string, + LOCKED_ERC721_MINTABLE_TOPIC: string, + LOCKED_ERC1155_MINTABLE_TOPIC: string, + + EXITED_ETHER_TOPIC: string, + FX_ERC20_WITHDRAW_TOPIC: string, + FX_ERC721_WITHDRAW_TOPIC: string, + FX_ERC20_MINTABLE_WITHDRAW_TOPIC: string, + FX_ERC721_MINTABLE_WITHDRAW_TOPIC: string, + + FX_ERC20_ROOT_TUNNEL: string, + FX_ERC721_ROOT_TUNNEL: string, + FX_ERC1155_ROOT_TUNNEL: string, + + FX_ERC20_TOPIC: string, + FX_ERC721_TOPIC: string, + FX_ERC1155_TOPIC: string, + + PLASMA_TOPIC: string, + PLASMA_CONFIRM_WITHDRAW_TOPIC: string, + PLASMA_EXIT_TOPIC: string, + PLASMA_ERC20_PREDICATE: string, + + STATE_SYNCED_TOPIC: string, + + ERC20_ERC721_TRANSFER_TOPIC: string, + NULL_ADDRESS_TOPIC: string, + NULL_ADDRESS: string, + ETH_ADDRESS: string, + + CUSTOM_WITHDRAW_TOPIC: string, + + PLASMA_BURN_TOPIC: string, + + CUSTOM_MAPPING_TOKEN_ADDRESS_1: string, + CUSTOM_MAPPING_TOKEN_ADDRESS_2: string, + CUSTOM_MAPPING_TOKEN_ADDRESS_3: string, + + CUSTOM_MAPPING_PREDICATE_ADDRESS: string, + + PLASMA_MAPPING_TOPIC: string, + POS_MAPPING_TOPIC: string, + FX_ERC20_MAPPING_TOPIC: string, + FX_ERC721_MAPPING_TOPIC: string, + FX_ERC1155_MAPPING_TOPIC: string, + + ERC20_TOKEN_TYPE: string, + ERC721_TOKEN_TYPE: string, + ERC1155_TOKEN_TYPE: string, + MINTABLE_ERC20_TOKEN_TYPE: string, + MINTABLE_ERC721_TOKEN_TYPE: string, + MINTABLE_ERC1155_TOKEN_TYPE: string, + CUSTOM_TOKEN_TYPE: string, + + CHECKPOINT_TOPIC: string +} diff --git a/internal/interfaces/consumer_config.ts b/internal/interfaces/consumer_config.ts new file mode 100644 index 0000000..0ea4b15 --- /dev/null +++ b/internal/interfaces/consumer_config.ts @@ -0,0 +1,19 @@ +import { ConsumerGlobalConfig } from "node-rdkafka"; +import { ConsumerTopicConfig } from "node-rdkafka"; +import { ICoderConfig } from "./coder_config.js"; +import { IKafkaCoderConfig } from "./kafka_coder_config.js"; + +export interface IConsumerConfig extends ConsumerGlobalConfig { + maxBufferLength?: number, + maxRetries?: number, + connectionTimeout?: number, + topicConfig?: ConsumerTopicConfig, + startOffsets?: { + [topic: string]: number + }, + topic?: string | string[], + coders?: IKafkaCoderConfig, + type?: string, + encoding?: string, + coderConfig?: ICoderConfig | ICoderConfig[] +} diff --git a/internal/interfaces/consumer_queue_object.ts b/internal/interfaces/consumer_queue_object.ts new file mode 100644 index 0000000..ef1a492 --- /dev/null +++ b/internal/interfaces/consumer_queue_object.ts @@ -0,0 +1,4 @@ +export interface IConsumerQueueObject { + message: T, + promise?: Promise +} diff --git a/internal/interfaces/deposit.ts b/internal/interfaces/deposit.ts new file mode 100644 index 0000000..953fc97 --- /dev/null +++ b/internal/interfaces/deposit.ts @@ -0,0 +1,15 @@ +import { TokenType } from "../enums/tokentype.js"; +import { BridgeType } from "../enums/bridgetype.js"; + +export interface IDeposit { + tokenType: TokenType, + bridgeType: BridgeType; + transactionHash: string, + depositor: string, + depositReceiver: string, + rootToken: string, + amounts?: string[], + tokenIds?: string[], + timestamp?: number, + rootTunnelAddress?: string +} diff --git a/internal/interfaces/deserialised_kafka_message.ts b/internal/interfaces/deserialised_kafka_message.ts new file mode 100644 index 0000000..4fd5373 --- /dev/null +++ b/internal/interfaces/deserialised_kafka_message.ts @@ -0,0 +1,5 @@ +import { Message } from "node-rdkafka"; + +export interface DeserialisedMessage extends Omit { + value?: object +} diff --git a/internal/interfaces/event_log.ts b/internal/interfaces/event_log.ts new file mode 100644 index 0000000..5bcf696 --- /dev/null +++ b/internal/interfaces/event_log.ts @@ -0,0 +1,13 @@ +import Long from "long"; + +export interface IEventLog { + address: string; + data: string; + logIndex: Long; + topics: string[]; + transactionHash: string; + transactionIndex: Long; + blockHash: string; + blockNumber: Long; + removed?: boolean; +} diff --git a/internal/interfaces/index.ts b/internal/interfaces/index.ts new file mode 100644 index 0000000..c071d2d --- /dev/null +++ b/internal/interfaces/index.ts @@ -0,0 +1,36 @@ +export * from "./async_observer.js"; +export * from "./block_getter_worker_promise.js"; +export * from "./block_getter.js"; +export * from "./block_header.js"; +export * from "./block_producer_config.js"; +export * from "./block_subscription.js"; +export * from "./block_worker_message.js"; +export * from "./block.js"; +export * from "./coder_config.js"; +export * from "./coder.js"; +export * from "./common_kafka_events.js"; +export * from "./config.js"; +export * from "./consumer_config.js"; +export * from "./consumer_queue_object.js"; +export * from "./deposit.js"; +export * from "./deserialised_kafka_message.js"; +export * from "./event_log.js"; +export * from "./kafka_coder_config.js"; +export * from "./logger_config.js"; +export * from "./mapper.js"; +export * from "./new_heads_subscriber.js"; +export * from "./observer.js"; +export * from "./producer_config.js"; +export * from "./quicknode_response.js"; +export * from "./raw_block.js"; +export * from "./raw_receipt.js"; +export * from "./raw_transaction.js"; +export * from "./rpc_payload.js"; +export * from "./sequential_consumer_config.js"; +export * from "./stream_api_block.js"; +export * from "./synchronous_producer.js"; +export * from "./transaction_receipt.js"; +export * from "./transaction.js"; +export * from "./transformed_block.js"; +export * from "./web3_transaction_receipt.js"; +export * from "./web3_transaction.js"; diff --git a/internal/interfaces/kafka_coder_config.ts b/internal/interfaces/kafka_coder_config.ts new file mode 100644 index 0000000..be0c55e --- /dev/null +++ b/internal/interfaces/kafka_coder_config.ts @@ -0,0 +1,5 @@ +import { ICoder } from "./coder.js"; + +export interface IKafkaCoderConfig { + [topic: string]: ICoder +} diff --git a/internal/interfaces/logger_config.ts b/internal/interfaces/logger_config.ts new file mode 100644 index 0000000..53ed63a --- /dev/null +++ b/internal/interfaces/logger_config.ts @@ -0,0 +1,17 @@ +import winston from "winston"; + +export interface LoggerConfig { + sentry?: { + dsn?: string, + level?: string, + environment?: string + } + datadog?: { + service_name?: string, + api_key?: string + } + console?: { + level?: string + } + winston?: winston.LoggerOptions; +} diff --git a/internal/interfaces/mapper.ts b/internal/interfaces/mapper.ts new file mode 100644 index 0000000..fd678b6 --- /dev/null +++ b/internal/interfaces/mapper.ts @@ -0,0 +1,4 @@ + +export interface IMapper { + map(data: T): G[]| Promise; +} diff --git a/internal/interfaces/new_heads_subscriber.ts b/internal/interfaces/new_heads_subscriber.ts new file mode 100644 index 0000000..d54c1b0 --- /dev/null +++ b/internal/interfaces/new_heads_subscriber.ts @@ -0,0 +1,6 @@ +import {Observer, Subscription } from "rxjs"; +import {IBlockHeader} from "./block_header.js"; + +export interface INewHeadsSubscriber { + createBlockSubscription(subscriber: Observer): Subscription +} diff --git a/internal/interfaces/observer.ts b/internal/interfaces/observer.ts new file mode 100644 index 0000000..b3a167d --- /dev/null +++ b/internal/interfaces/observer.ts @@ -0,0 +1,5 @@ +export interface IObserver { + next: (value: T) => Promise | void + error: (value: E) => void + closed: () => void +} diff --git a/internal/interfaces/producer_config.ts b/internal/interfaces/producer_config.ts new file mode 100644 index 0000000..770fbc2 --- /dev/null +++ b/internal/interfaces/producer_config.ts @@ -0,0 +1,15 @@ +import { ProducerGlobalConfig } from "node-rdkafka"; +import { ICoder } from "../interfaces/coder.js"; +import { ICoderConfig } from "./coder_config.js"; + +export interface IProducerConfig extends ProducerGlobalConfig { + topic: string; + pollInterval?: number, + connectionTimeout?: number, + flushTimeout?: number, + deliveryTimeout?: number, + type?: string, + coder?: ICoder, + encoding?: string, + coderConfig?: ICoderConfig +} diff --git a/internal/interfaces/quicknode_response.ts b/internal/interfaces/quicknode_response.ts new file mode 100644 index 0000000..52d173b --- /dev/null +++ b/internal/interfaces/quicknode_response.ts @@ -0,0 +1,7 @@ +import { IRawReceipt } from "./raw_receipt.js"; +import { IRawBlock } from "./raw_block.js"; + +export interface IQuickNodeResponse { + block: IRawBlock, + receipts: IRawReceipt[] +} diff --git a/internal/interfaces/raw_block.ts b/internal/interfaces/raw_block.ts new file mode 100644 index 0000000..1f00e01 --- /dev/null +++ b/internal/interfaces/raw_block.ts @@ -0,0 +1,24 @@ +import { IRawTransaction } from "./raw_transaction.js"; + +export interface IRawBlock { + difficulty: string; + totalDifficulty: string; + number: string; + gasLimit: string; + baseFeePerGas?: string; + gasUsed: string; + logsBloom: string; + hash: string; + parentHash: string; + receiptsRoot: string; + sha3Uncles: string; + size: string; + stateRoot: string; + timestamp: string; + transactionsRoot: string; + miner: string; + nonce: string; + extraData: string; + transactions: IRawTransaction[]; + uncles?: string[]; +} diff --git a/internal/interfaces/raw_receipt.ts b/internal/interfaces/raw_receipt.ts new file mode 100644 index 0000000..2a4662c --- /dev/null +++ b/internal/interfaces/raw_receipt.ts @@ -0,0 +1,27 @@ +export interface IRawEventLog { + address: string; + data: string; + logIndex: string; + topics: string[]; + transactionHash: string; + transactionIndex: string; + blockHash: string; + blockNumber: string; + removed?: boolean; +} + +export interface IRawReceipt { + transactionHash: string; + transactionIndex: string; + from: string; + to: string + blockNumber: string; + blockHash: string; + contractAddress?: string; + gasUsed: string; + cumulativeGasUsed: string; + logs: IRawEventLog[]; + logsBloom: string; + status: string; + effectiveGasPrice?: string; +} diff --git a/internal/interfaces/raw_transaction.ts b/internal/interfaces/raw_transaction.ts new file mode 100644 index 0000000..00a813c --- /dev/null +++ b/internal/interfaces/raw_transaction.ts @@ -0,0 +1,15 @@ +export interface IRawTransaction { + hash: string, + nonce: string, + blockHash: string | null, + blockNumber: string, + transactionIndex?: string, + from: string, + to: string | null, + value: string | string, + gasPrice: string | string, + gas: string, + input: string, + maxFeePerGas?: string, + maxPriorityFeePerGas?: string, +} diff --git a/internal/interfaces/rpc_payload.ts b/internal/interfaces/rpc_payload.ts new file mode 100644 index 0000000..e1cc5ad --- /dev/null +++ b/internal/interfaces/rpc_payload.ts @@ -0,0 +1,4 @@ +export interface IRPCPayload { + method: string, + params?: string[] +} diff --git a/internal/interfaces/sequential_consumer_config.ts b/internal/interfaces/sequential_consumer_config.ts new file mode 100644 index 0000000..d09872e --- /dev/null +++ b/internal/interfaces/sequential_consumer_config.ts @@ -0,0 +1,6 @@ +import { ConsumerGlobalConfig } from "node-rdkafka"; + +export interface ISequentialConsumerConfig { + maxBufferLength?: number, + maxRetries?: number, +} diff --git a/internal/interfaces/stream_api_block.ts b/internal/interfaces/stream_api_block.ts new file mode 100644 index 0000000..ed854d2 --- /dev/null +++ b/internal/interfaces/stream_api_block.ts @@ -0,0 +1,68 @@ +type Log = { + lid: string; + address: string; + topics: string[]; + data: string; + blockNumber: string; + transactionIndex: string; + logIndex: string; + removed: boolean; +} + +type Account = { + "@type": "Account"; + address: string; +} + +type Transaction = { + hash: string; + blockNumber: string + from: Account + gas: string + gasPrice: string + maxFeePerGas: string + maxPriorityFeePerGas: string + input: string + nonce: string + to: Account + transactionIndex: string + value: string + fee: string + type: string + chainId: string + v: string + r: string + s: string + logsBloom: string + root: string + contractAddress: string + cumulativeGasUsed: string + gasUsed: string + status: string + logs: Log[] +} + +export interface IStreamApiBlock { + hash: string; + number: string; + baseFeePerGas: string; + difficulty: string; + extraData: string; + gasLimit: string; + gasUsed: string; + logsBloom: string; + miner: Account; + mixHash: string; + nonce: string; + parentHash: string; + receiptsRoot: string; + sha3Uncles: string; + size: string + stateRoot: string + timestamp: string + totalDifficulty: string + transactions: Transaction[] + transactionsRoot: string + ommerCount: string + logs: Log[] +} diff --git a/internal/interfaces/synchronous_producer.ts b/internal/interfaces/synchronous_producer.ts new file mode 100644 index 0000000..06a000c --- /dev/null +++ b/internal/interfaces/synchronous_producer.ts @@ -0,0 +1,16 @@ +import { DeliveryReport, LibrdKafkaError } from "node-rdkafka"; +import { KafkaProducerEvents, EventListener } from "./common_kafka_events.js"; + +export interface ISynchronousProducer { + produceEvent( + topic: string, + key: string, + message: object, + protobufMessageType: string, + partition?: number, + timestamp?: number, + ): Promise + + once(event: E, listener: EventListener): this; + on(event: E, listener: EventListener): this; +} diff --git a/internal/interfaces/transaction.ts b/internal/interfaces/transaction.ts new file mode 100644 index 0000000..5d3bc37 --- /dev/null +++ b/internal/interfaces/transaction.ts @@ -0,0 +1,25 @@ +import Long from "long"; +import { StringLiteralLike } from "typescript"; +import { ITransactionReceipt } from "./transaction_receipt.js"; + +export interface ITransaction { + hash: string, + nonce: Long, + blockHash: string | null, + blockNumber: Long | null, + transactionIndex: Long | null, + from: string, + to: string | null, + value: string, + gasPrice: string, + gas: Long, + input: string, + maxFeePerGas?: string, + maxPriorityFeePerGas?: string, + chainId: string, + v: string, + r: string, + s: string, + type: number, + receipt: ITransactionReceipt +} diff --git a/internal/interfaces/transaction_receipt.ts b/internal/interfaces/transaction_receipt.ts new file mode 100644 index 0000000..71ab06b --- /dev/null +++ b/internal/interfaces/transaction_receipt.ts @@ -0,0 +1,18 @@ +import { IEventLog } from "./event_log.js"; +import Long from "long"; + +export interface ITransactionReceipt { + transactionHash: string; + transactionIndex: Long; + from: string; + to: string + blockNumber: Long; + blockHash: string; + contractAddress?: string | null; //Have to add null as web3.js types are incorrect. + gasUsed: Long; + cumulativeGasUsed: Long; + logs: IEventLog[]; + logsBloom: string; + status: boolean; + effectiveGasPrice?: string; +} diff --git a/internal/interfaces/transformed_block.ts b/internal/interfaces/transformed_block.ts new file mode 100644 index 0000000..0da811f --- /dev/null +++ b/internal/interfaces/transformed_block.ts @@ -0,0 +1,7 @@ +import Long from "long"; + +export interface ITransformedBlock { + blockNumber: Long, + timestamp: Long, + data: T[] +} diff --git a/internal/interfaces/web3_transaction.ts b/internal/interfaces/web3_transaction.ts new file mode 100644 index 0000000..7f31a61 --- /dev/null +++ b/internal/interfaces/web3_transaction.ts @@ -0,0 +1,9 @@ +import { Transaction } from "web3-core"; + +export interface IWeb3Transaction extends Transaction { + chainId: string; + v: string; + r: string; + s: string; + type: number; +} diff --git a/internal/interfaces/web3_transaction_receipt.ts b/internal/interfaces/web3_transaction_receipt.ts new file mode 100644 index 0000000..da9cd1e --- /dev/null +++ b/internal/interfaces/web3_transaction_receipt.ts @@ -0,0 +1,5 @@ +import { TransactionReceipt } from "web3-core"; + +export interface IWeb3TransactionReceipt extends Omit { + effectiveGasPrice?: string | number; +} diff --git a/internal/kafka/consumer/abstract_consumer.ts b/internal/kafka/consumer/abstract_consumer.ts new file mode 100644 index 0000000..d395579 --- /dev/null +++ b/internal/kafka/consumer/abstract_consumer.ts @@ -0,0 +1,459 @@ +import noderdkafka, { Metadata, LibrdKafkaError, Message, TopicPartition } from "node-rdkafka"; +import { DeserialisedMessage } from "../../interfaces/deserialised_kafka_message.js"; +import { IConsumerQueueObject } from "../../interfaces/consumer_queue_object.js"; +import { IConsumerConfig } from "../../interfaces/consumer_config.js"; +import { IKafkaCoderConfig } from "../../interfaces/kafka_coder_config.js"; +import { isBaseError } from "../../errors/is_base_error.js"; +import { IObserver } from "../../interfaces/observer.js"; +import { KafkaError } from "../../errors/kafka_error.js"; +import { BaseError } from "../../errors/base_error.js"; +import { Logger } from "../../logger/logger.js"; +import { Queue } from "../../queue/queue.js"; + +/** + * Abstract Consumer class wraps the Producer class of Node-RdKafka and provides simple straightforward methods to start producing events to Kafka. + * Connection is handled by the class internally and an option to create the connection manually is also provided. Connecting manually allows to get the + * metadata details and also avoid latency involved in creating a connection on production of first event. + * Each public method follows a promised based error handling pattern to report thrown during the execution of the method. + * To capture all exceptions that may occur internally in the library outside the execution of a method, error event is emitted which can be subscribed to. + * @extends noderdkafka.KafkaConsumer + * @author Vibhu Rajeev - Polygon Technology - 2022 + */ +export abstract class AbstractConsumer extends noderdkafka.KafkaConsumer { + private consumerPaused: boolean = false; + private maxBufferLength: number; + private connectionTimeout: number; + private consumerConnected: boolean = false; + private consumerConnecting: boolean = false; + private consumerConnectPromise: Promise | null = null; + private brokerMetadata: Metadata | null = null; + private queueIsProcessing: boolean = false; + private startOffsets: { + [topic: string]: number + }; + protected topics: string[]; + protected maxRetries: number; + protected queue: Queue>; + protected observer: IObserver | null = null; + private seekCalled: boolean = false; + + /** + * @param {string|string[]} topic - The default topic that the consumer will subscribe to in case not specified in the method. + * @param {IKafkaCoderConfig} coders - Object with coder instances where key is the topic name. + * @param {IConsumerConfig} config - Key value pairs to override the default config of the consumer client. + * The following additional config can also be set: + * 1. [maxBufferLength=100] - The maximum length of the internal buffer exceeding which consumer will be paused. + * 2. [maxRetries=10] - Number of times to retry executing the onData promise before giving up. + * 3. [flushTimeout=10000] - Timeout in milliseconds before which the buffer of internal producer client should be cleared when the disconnect method is called. + */ + constructor( + topic: string | string[], + private coders: IKafkaCoderConfig, + config: IConsumerConfig = {} + ) { + // Has to be done otherwise Kafka will complain (they have runtime checks) + const maxBufferLength = config.maxBufferLength || 100; + const maxRetries = config.maxRetries || config.maxRetries === 0 ? config.maxRetries : 10; + const connectionTimeout = config.connectionTimeout || 10000; + const topicConfig = config.topicConfig || {}; + const startOffsets = config.startOffsets || {}; + + delete config.maxBufferLength; + delete config.maxRetries; + delete config.connectionTimeout; + delete config.topicConfig; + delete config.startOffsets; + + super( + Object.assign({ + "debug": "cgrp", + "bootstrap.servers": "localhost:9092", + "enable.auto.commit": false, + "enable.auto.offset.store": false, + "event_cb": true, + "message.max.bytes": 26214400, + "fetch.message.max.bytes": 26214400, + "queued.max.messages.kbytes": 25000 + }, config), + Object.assign( + { + "auto.offset.reset": "earliest", + }, + topicConfig + ) + ); + + //Below is required to not break current implementations. TODO: Apply changes with a breaking change. + if (Array.isArray(topic)) { + this.topics = topic; + } else { + this.topics = [topic]; + } + + this.queue = new Queue(); + this.maxBufferLength = maxBufferLength; + this.maxRetries = maxRetries; + this.connectionTimeout = connectionTimeout; + this.startOffsets = startOffsets; + } + + /** + * This method must be implemented by the subclasses. This method is called before adding the message to queue. + * It must be used to call promises concurrently, before adding to queue. + * + * @param {DeserialisedMessage} message - The Deserialised message to perform any action on. + * @returns {IConsumerQueueObject} - The method needs to return an object that implements interface IConsumerQueueObject. + */ + protected abstract enqueue(message: DeserialisedMessage): IConsumerQueueObject; + + /** + * Private internal method to connect to the broker and return broker metadata. + * + * @returns {Promise} A promise which resolves to give the metadata of connected. + * + * @throws {KafkaError} - On failure to connect, rejects with the kafka error. + */ + private connectToBroker(): Promise { + return new Promise((resolve, reject) => { + // The method can be expanded in future to allow requesting metadata of specific topics along with broker details. + this.consumerConnecting = true; + this.connect({ timeout: this.connectionTimeout }, (error: LibrdKafkaError, metadata: Metadata) => { + this.consumerConnecting = false; + if (error) { + reject( + KafkaError.convertLibError(error) + ); + + return; + } + + this.consumerConnected = true; + this.brokerMetadata = metadata; + + Logger.info(this.brokerMetadata); + resolve(metadata); + }); + }); + } + + /** + * The private internal method, that pauses or resumes the consumer based on the current + * length of internal buffer. + * + * @param message {DeserialisedMessage} - The latest message added to the queue. + * + * @returns {void} + */ + private handleBackpressure(message: DeserialisedMessage): void { + if (!this.consumerPaused && this.maxBufferLength <= this.queue.getLength()) { + this.pause([message as TopicPartition]); + this.consumerPaused = true; + + return; + } + + if (this.consumerPaused && this.queue.getLength() < this.maxBufferLength) { + this.resume([message as TopicPartition]); + this.consumerPaused = false; + } + } + + /** + * @async + * Protected method, which deserialises the kafka message and adds it to the internal queue. + * It also then calls handlebackPressure() and processQueue() after the message is added to the queue. + * + * @param {Message} message - The kafka message, value of which needs to be deserialised. + * + * @throws {KafkaError|CoderError} - Throws CoderError or KafkaError on failure to deserialise or add the message to queue. + */ + protected async onData(message: Message): Promise { + //Skip processing the message if behind start offset. + if (message.offset < (this.startOffsets[message.topic] || 0)) { + if (!this.seekCalled) { + Logger.info(`Seeking offset number: ${this.startOffsets[message.topic]}, for topic: ${message.topic}`); + await new Promise( + (res, rej) => this.seek({ + topic: message.topic, + offset: this.startOffsets[message.topic], + partition: message.partition + }, this.connectionTimeout, (err) => { + if (err) { + return rej(err); + } + + res(undefined); + }) + ); + this.seekCalled = true; + } + + return; + } + + const deserializedMsg = await this.deserialize(message); + this.queue.enqueue(this.enqueue(deserializedMsg)); + this.handleBackpressure(deserializedMsg); + this.processQueue(); + } + + /** + * Internal private method to commitMessage and retry on failure upto maxRetries. + * + * @param {Message} message - Kafka message to be committed to cluster. + * + * @param {number} errorCount - This param must not be set externally and is used to track errorCount. + */ + private safeCommitMessage(message: Message, errorCount: number = 0): void { + try { + this.commitMessage(message); + } catch (error) { + // TODO - skip retry if fatal error + if (this.maxRetries <= errorCount) { + this.onError(KafkaError.createUnknown(error as LibrdKafkaError)); + + return; + } + + return this.safeCommitMessage(message, errorCount + 1); + } + } + + /** + * Private internal method that is used to process a queue of messages, commit its offset after successful processing/ + * On failure after maximum retries of processing a message, the queue is cleared and error function of the observer is called. + * + * @returns {Promise} + */ + private async processQueue(): Promise { + if (!this.observer) { + throw new KafkaError("Kafka Consumer Error", KafkaError.codes.CONSUMER_OBSERVER_INVALID, true, "Observer is not set", "local"); + } + + if (this.queueIsProcessing) { + return; + } + + let errorCount: number = 0; + this.queueIsProcessing = true; + + while (!this.queue.isEmpty()) { + try { + const element: IConsumerQueueObject = this.queue.front() as IConsumerQueueObject; + + if (element.promise) { + await element.promise; + } else { + await this.observer.next(element.message); + } + + this.safeCommitMessage(element.message as Message); + this.queue.shift(); + this.handleBackpressure(element.message); + errorCount = 0; + } catch (error) { + errorCount++; + if (errorCount > this.maxRetries || (isBaseError(error) && (error as BaseError).isFatal)) { + this.onError( + KafkaError.createUnknown(error) + ); + + return; + } + } + } + + this.queueIsProcessing = false; + } + + /** + * @async + * Private internal method to deserialise every message. + * + * @param {Messsage} message - Kafka message of which the value needs to be deserialised + * + * @returns {Promise} - The LibRdKafka message object with deserialised message value. + * + * @throws {CoderError} - Throws coder error on failure to deserialise. + */ + private async deserialize(message: Message): Promise { + if (message.value) { + Object.assign( + message, + { + value: await this.coders[message.topic].deserialize(message.value) + } + ); + } + + return message as DeserialisedMessage; + } + + + /** + * Internal method which clears the queue and diconnects the kafka consumer on fatal + * error, and always informs the observer about any error + * + * @param {BaseError} error - The error object to be acted on. + * + * @returns {void} + */ + protected onError(error: BaseError): void { + if (error.isFatal) { + this.queue.clear(); + this.stop(); + } + + this.observer?.error(error); + } + + /** + * Private method which updates the connection status of consumer to disconnected, and removes all listeners. + * + * @returns {void} + */ + private onDisconnect(): void { + if (this.consumerConnected || this.brokerMetadata || !this.queue.isEmpty()) { + this.queue.clear(); + this.brokerMetadata = null; + this.consumerConnected = false; + this.observer?.closed(); + this.removeAllListeners(); + } + } + + /** + * Private internal method to subscribe a consumer to a single topic and start consuming from previously committed offset. + * + * @returns {Promise} + */ + private async createSubscription(): Promise { + try { + if (!this.consumerConnected) { + await this.createConnection(); + } + + // Can alternatively use this.assign(); + this.subscribe(this.topics); + + // if (Object.keys(this.startOffsets).length) { + // await new Promise(r => setTimeout(r, 10000)); + // for (let topic of Object.keys(this.startOffsets)) { + // Logger.info(`Seeking offset number: ${this.startOffsets[topic]}, for topic: ${topic}`); + + // await new Promise( + // (res, rej) => this.seek({ + // topic: topic, + // offset: this.startOffsets[topic], + // partition: 0 + // }, this.connectionTimeout, (err) => { + // if (err) { + // return rej(err); + // } + + // res(undefined); + // }) + // ); + // } + // } + + this.consume(); + } catch (error) { + throw KafkaError.createUnknown(error); + } + } + + /** + * @async + * Method to connect the consumer to broker and update the connection status in the class. + * This method is called internally when produceEvent() method is called if consumer is not connected. + * In cases where it may be beneficial to connect the consumer in advance, it may be called by an external caller. + * If there is an already existing promise to connect to broker, the method will wait for the original promise to resolve. + * + * @returns {Promise} - The promise resolves to give the object containing the metadata of broker that + * the consumer is connected to and the topics available in that broker or the error thrown during connection. + * + * @throws {KafkaError} - Throws error object on failure. + */ + public async createConnection(): Promise { + if (Object.keys(this.coders).length !== this.topics.length) { + throw new KafkaError( + "Invalid coder config", + KafkaError.codes.INVALID_CODER_CONFIG, + true, + "Coder configuration is not set for every topic.", + "local" + ); + } + + this.topics.forEach((topic) => { + if (!this.coders[topic]) { + throw new KafkaError( + "Invalid coder config", + KafkaError.codes.INVALID_CODER_CONFIG, + true, + "Coder config does not match topic names.", + "local" + ); + } + }); + + if (!this.consumerConnecting && !this.consumerConnected) { + this.consumerConnectPromise = this.connectToBroker(); + } + + return this.brokerMetadata ? this.brokerMetadata : await this.consumerConnectPromise as Metadata; + } + + /** + * @async + * The main entry point to start consuming events. This method returns an observable object which on subscription + * connects the consumer to a broker if not connection and creates a stream of messages consumed from kafka. + * Calling this event, creates a new stream everytime. + * + * @param {Observer} observer - Th observer object to be passed consisting of next(), error(), and closed(). + * next() method is the promise method to be called for every event. + * + * @returns {Promise} - This method on resolving does not return any value. + * + * @throws {KafkaError} - Throws KafkaError on failure to connect or subscribe to the topic. + */ + public async start(observer: IObserver): Promise { + if (this.listenerCount("event.error") || this.listenerCount("data") || this.listenerCount("disconnected")) { + this.removeAllListeners(); + } + + this.observer = observer; + + this.on("event.error", + (error: LibrdKafkaError) => this.onError( + KafkaError.convertLibError(error) + )) + .on("data", + async (message: Message) => { + try { + await this.onData(message); + } catch (error) { + this.onError(KafkaError.createUnknown(error)); + } + }) + .on("disconnected", this.onDisconnect.bind(this)); + + await this.createSubscription(); + } + + /** + * Public method that must be called to stop consuming kafka events. It de registers all listeners and disconnects from brokers. + * + * @returns {void} + */ + public stop(): void { + this.disconnect((err: unknown) => { + if (err) { + Logger.error(KafkaError.createUnknown(err)); + } + + this.onDisconnect(); + }); + } +} diff --git a/internal/kafka/consumer/asynchronous_consumer.ts b/internal/kafka/consumer/asynchronous_consumer.ts new file mode 100644 index 0000000..57e6e27 --- /dev/null +++ b/internal/kafka/consumer/asynchronous_consumer.ts @@ -0,0 +1,50 @@ +import { BaseError } from "../../errors/base_error.js"; +import { AbstractConsumer } from "./abstract_consumer.js"; +import { DeserialisedMessage } from "../../interfaces/deserialised_kafka_message.js"; +import { IConsumerQueueObject } from "../../interfaces/consumer_queue_object.js"; +import { isBaseError } from "../../errors/is_base_error.js"; +import { KafkaError } from "../../errors/kafka_error.js"; + +/** + * The AsynchronousConsumer extends AbstractConsumer class to provide guarantee of + * ordered committing of offsets. The messages are processed concurrently using the event loop, + * but offsets are committed in order. If an earlier promise in the queue fails, later offsets will + * not be comitted even if successful. + * @extends AbstractConsumer + */ +export class AsynchronousConsumer extends AbstractConsumer { + /** + * Private method to be used as a wrapper to retry the next promise internally upto max retries by using recursive calls. + * + * @param {DeserialisedMessage} message - The Deserialised message to be passed to the next promise. + * + * @param {number} errorCount - This param should not be set externally and is used by recursive calls to track the number of times next promise failed. + * + * @returns {Promise} + */ + private async retryPromise(message: DeserialisedMessage, errorCount: number = 0): Promise { + try { + await this.observer?.next(message); + } catch (error) { + if (errorCount >= this.maxRetries || (isBaseError(error) && (error as BaseError).isFatal)) { + throw KafkaError.createUnknown(error); + } + + return this.retryPromise(message, errorCount + 1); + } + } + + /** + * Implementation of the abstract enqueue method. This implementation adds queue object with the wrapped retryPromise to the queue + * + * @param {DeserialisedMessage} message - The message of which queue object needs to be added to the internal queue. + * + * @returns {IConsumerQueueObject} - Returns consumer queue object with the observer.next wrapped in next promise. + */ + protected enqueue(message: DeserialisedMessage): IConsumerQueueObject { + return { + message, + promise: this.retryPromise(message) + }; + } +} diff --git a/internal/kafka/consumer/synchronous_consumer.ts b/internal/kafka/consumer/synchronous_consumer.ts new file mode 100644 index 0000000..5cb6889 --- /dev/null +++ b/internal/kafka/consumer/synchronous_consumer.ts @@ -0,0 +1,24 @@ +import { AbstractConsumer } from "./abstract_consumer.js"; +import { DeserialisedMessage } from "../../interfaces/deserialised_kafka_message.js"; +import { IConsumerQueueObject } from "../../interfaces/consumer_queue_object.js"; + +/** + * The SynchronousConsumer extends AbstractConsumer class to provide guarantee of + * synchronous one at a time processing of events and committing of offsets. The class maintains the new events in an + * internal buffer and only moves to the next event after successful processing of the previous one. In case of exception, + * The queue is cleared, on a maximum number of retries that can be set via config. The class also internally handles + * back pressure by pausing the consumer if buffer exceeds the maximum limit. + * @extends AbstractConsumer + */ +export class SynchronousConsumer extends AbstractConsumer { + /** + * Implementation of the abstract enqueue method. This implementation adds queue object with the wrapped retryPromise to the queue + * + * @param {DeserialisedMessage} message - The message of which queue object needs to be added to the internal queue. + * + * @returns {IConsumerQueueObject} - Returns consumer queue object without the observer.next promise. + */ + protected enqueue(message: DeserialisedMessage): IConsumerQueueObject { + return {message}; + } +} diff --git a/internal/kafka/producer/abstract_producer.ts b/internal/kafka/producer/abstract_producer.ts new file mode 100644 index 0000000..b34c10a --- /dev/null +++ b/internal/kafka/producer/abstract_producer.ts @@ -0,0 +1,267 @@ +import noderdkafka, { LibrdKafkaError, Metadata } from "node-rdkafka"; +import { KafkaProducerEvents, EventListener } from "../../interfaces/common_kafka_events.js"; +import { IProducerConfig } from "../../interfaces/producer_config.js"; +import { ICoder } from "../../interfaces/coder.js"; +import { KafkaError } from "../../errors/kafka_error.js"; + + +/** + * Producer class wraps the Producer class of Node-RdKafka and provides simple straightforward methods to start producing events to Kafka. + * Connection is handled by the class internally and an option to create the connection manually is also provided. + * Connecting manually allows to get the metadata details and also avoid latency involved in creating a connection on production of first event. + * Each public method follows a promised based error handling pattern to report thrown during the execution of the method. + * To capture all exceptions that may occur internally in the library or the kafka producer client, error event ('producer.error') is emitted which can be subscribed to. + * @extends noderdkafka.Producer + */ +export abstract class AbstractProducer extends noderdkafka.Producer { + private topic: string; + private producerConnected: boolean = false; + private producerConnecting: boolean = false; + private producerConnectPromise?: Promise; + private pollInterval: number; + private connectionTimeout: number; + private flushTimeout: number; + private stopProducerPromise?: Promise; + private static readonly DISCONNECTED: string = "producer.disconnected"; + private static readonly ERROR: string = "producer.error"; + + /** + * @param {Coder} serialiser - The Serialiser object to serialise messages before production. + * @param {IProducerConfig} config - Key value pairs to override the default config of the producer client. + */ + constructor( + private serialiser: ICoder, + config: IProducerConfig + ) { + // This has to be done cause otherwise Kafka complains + const pollInterval = config.pollInterval || 1000; + const connectionTimeout = config.connectionTimeout || 10000; + const flushTimeout = config.flushTimeout || 10000; + const topic = config.topic; + + delete config.pollInterval; + delete config.connectionTimeout; + delete config.flushTimeout; + delete (config as any).topic; + + super( + Object.assign( + { + "bootstrap.servers": "localhost:9092", + "dr_cb": true, + "enable.idempotence": true, + "acks": -1 + }, + config + ) + ); + + this.pollInterval = pollInterval; + this.connectionTimeout = connectionTimeout; + this.flushTimeout = flushTimeout; + this.topic = topic; + } + + once(event: "producer.error", listener: (error: KafkaError) => void): this; + once(event: "producer.disconnected", listener: () => void): this; + once(event: E, listener: EventListener): this; + once(event: Event, listener: EventListener): this { + //@ts-ignore + return super.once(event, listener); + } + + on(event: "producer.error", listener: (error: KafkaError) => void): this; + on(event: "producer.disconnected", listener: () => void): this; + on(event: E, listener: EventListener): this; + on(event: Event, listener: EventListener): this { + //@ts-ignore + return super.on(event, listener); + } + + /** + * Private internal method to connect to the broker and subscribe to the librdkafka events. + * + * @returns {Promise} A promise which resolves to give the metadata of connected broker or rejects with the error that caused connection failure. + */ + private connectToBroker(): Promise { + return new Promise((resolve, reject) => { + this.on("event.error", + (error: LibrdKafkaError) => { + this.onKafkaError( + KafkaError.convertLibError(error, true) + ); + } + ) + .on("disconnected", this.onDisconnected.bind(this)); + + this.producerConnecting = true; + // The method can be expanded in future to allow requesting metadata of specific topics along with broker details. + this.connect({ timeout: this.connectionTimeout }, (error: LibrdKafkaError, metadata: Metadata) => { + this.producerConnecting = false; + if (error) { + reject(error); + + return; + } + + this.setPollInterval( this.pollInterval); + this.producerConnected = true; + resolve(metadata); + }); + }); + } + + /** + * Private internal method to handle connection internally when disconnected from broker + * and if no re connection is achieved emit disconnected event. + * + * @returns {void} + */ + private onDisconnected(): void { + //Can further implement reconnecting logic failing which, disconnected event will be emitted. + this.producerConnected = false; + this.emit(AbstractProducer.DISCONNECTED); + this.removeAllListeners("event.error"); + this.removeAllListeners("disconnected"); + } + + /** + * Internal private method to emit error event when librdkafka reports an error. + * + * @param {LibrdKafkaError} error - Error object to be emitted. + * + * @returns {void} + */ + private onKafkaError(error: KafkaError): void { + this.emit(AbstractProducer.ERROR, error); + + return; + } + + /** + * @async + * Method to connect the producer to broker and update the connection status in the class. + * This method is called internally when produceEvent() method is called if producer is not connected. + * In cases where it may be beneficial to connect the producer in advance, it may be called by an external caller. + * If there is an already existing promise to connect to broker, the method will wait for the original promise to resolve. + * + * @returns {Promise} - The object containing the metadata of broker that the producer is connected to + * and the topics available in that broker or the error thrown during connection. + */ + public async start(): Promise { + try { + if (! this.producerConnecting && ! this.producerConnected) { + this.producerConnectPromise = this.connectToBroker(); + } + const brokerMetadata: Metadata = await this.producerConnectPromise as Metadata; + return brokerMetadata; + } catch (error) { + this.producerConnecting = false; + throw KafkaError.createUnknown(error, true); + } + } + + /** + * @async + * This method serialises and sends the message to the internal producer client. It resolves on successful adding of + * event to internal producer buffer which means it does not guarantee delivery of message to kafka cluster. + * The method throws an error on failure which is usually when the queue is full. It is recommended to listen + * "delivered" event for confirmation and set "acks" setting to -1 which is the default setting. + * + * @param {string} key - The key associated with the message. + * @param {object} message - The message object to produce to kafka + * @param {string} topic - The topic name to produce the event to. + * @param {number} partition - To manually set the partition number of the topic to which the event needs to be produced to. + * @param {number} timestamp - To manually set the timestamp (Unix in ms) of the message. + * @param {object} opaque - Per-message opaque pointer that will be provided in the delivery report callback (dr_cb) for referencing this message. + * + * @returns {Promise} - Throws an error if it failed, or resolves to "true" if not + * + * @throws {LibrdKafkaError|Error} - Throws the exception behind the failure. + */ + public async sendToInternalProducer( + key: string, + message: object, + topic: string = this.topic, + partition?: number, + timestamp?: number, + opaque?: object + ): Promise { + try { + if (! this.producerConnected) { + await this.start(); + } + // TODO: Runtime check for all parameters + const produced = await this.produce( + topic, + partition, + await this.serialiser.serialize(message) as Buffer, + key, + timestamp, + opaque + ); + + if (produced === true) { + return produced; + } + + throw produced; + } catch (error) { + this.onKafkaError(KafkaError.createUnknown(error, true)); + + throw KafkaError.createUnknown(error, true); + } + } + + /** + * This methods clears the internal client buffer by sending all the messages and on success disconnects the producer client from clust + * + * @returns {true} - Returns true on successful disconnection. The producer still disconnects on failure to flush before timeout. + * + * @throws {LibrdKafkaError} - Throws any error faced during flushing or disconnecting. + */ + public async stop(): Promise { + try { + if (!this.stopProducerPromise) { + this.stopProducerPromise = new Promise((resolve, reject) => { + this.disconnect( this.flushTimeout, (error: LibrdKafkaError) => { + if (error) { + return reject(KafkaError.convertLibError(error)); + } + + return resolve(true); + }); + }); + } + + await this.stopProducerPromise; + + this.stopProducerPromise = undefined; + + return true; + } catch (error) { + this.stopProducerPromise = undefined; + + throw error; + } + } + + /** + * @param {string} topic - The topic name to produce the event to. + * @param {string} key - The key associated with the message. + * @param {object} message - The message object to produce to kafka + * @param {number} partition - To manually set the partition number of the topic to which the event needs to be produced to. + * @param {number} timestamp - To manually set the timestamp (Unix in ms) of the message. + * @param {object} opaque - Per-message opaque pointer that will be provided in the delivery report callback (dr_cb) for referencing this message. + * + * @returns {Promise} - Returns an error if it failed, or true if not + */ + public abstract produceEvent( + key: string, + message: object, + topic?: string, + partition?: number, + timestamp?: number, + opaque?: object + ): Promise +} diff --git a/internal/kafka/producer/asynchronous_producer.ts b/internal/kafka/producer/asynchronous_producer.ts new file mode 100644 index 0000000..122f92a --- /dev/null +++ b/internal/kafka/producer/asynchronous_producer.ts @@ -0,0 +1,96 @@ +import { LibrdKafkaError, DeliveryReport } from "node-rdkafka"; +import { ICoder } from "../../interfaces/coder.js"; +import { AbstractProducer, } from "./abstract_producer.js"; +import { IProducerConfig } from "../../interfaces/producer_config.js"; +import { KafkaProducerEvents, EventListener } from "../../interfaces/common_kafka_events.js"; +import { KafkaError } from "../../errors/kafka_error.js"; + +/** + * This class is to be used for sending events to kafka producer internal buffer. + * The class extends the Abstract producer class to emit delivered events which can be subscribed to for guarantee of delivery and + * appropriate error handling. + * @extends AbstractProducer + */ +export class AsynchronousProducer extends AbstractProducer { + private static readonly DELIVERED: string = "delivered"; + + /** + * @param {Coder} serialiser - The Serialiser object to serialise messages before production. + * @param {IProducerConfig} config - Key value pairs to override the default config of the producer client. + * Config related to broker connection can also be added. The possible values are: + * 1. [pollInterval=1000] - Interval in milliseconds at which client polls the broker for delivery reports. + * 2. [connectionTimeout=5000] - Timeout in milliseconds for successful connection to kafka cluster and retrieving of metadata. + * 3. [flushTimeout=10000] - Timeout in milliseconds before which the buffer of internal producer client should be cleared when the disconnect method is called. + */ + constructor( + serialiser: ICoder, + config: IProducerConfig + ) { + super(serialiser, config); + } + + /** + * Private internal method which emits delivered event on successful delivery or emits error event on exceptions. + * + * @param {LibrdKafkaError} error - Error object returned by librdkafka in case of failure to retrieve reports. + * @param {DeliveryReport} report - Delivery Report object returned by kafka with details of the delivered record/event after successful delivery to cluster. + * + * @returns {void} + */ + private onDeliveryReport(error: LibrdKafkaError, report: DeliveryReport): void { + if (report) { + this.emit(AsynchronousProducer.DELIVERED, report); + + return; + } + } + + //TODO - to rewrite the overloads and reduce the redundancy + once(event: "producer.error", listener: (error: KafkaError) => void): this; + once(event: "producer.disconnected", listener: () => void): this; + once(event: "delivered", listener: (report: DeliveryReport) => void): this + once(event: E, listener: EventListener): this; + once(event: Event, listener: EventListener): this { + //@ts-ignore + return super.once(event, listener); + } + + //TODO - to rewrite the overloads and reduce the redundancy + on(event: "producer.error", listener: (error: KafkaError) => void): this; + on(event: "producer.disconnected", listener: () => void): this; + on(event: "delivered", listener: (report: DeliveryReport) => void): this + on(event: E, listener: EventListener): this; + on(event: Event, listener: EventListener): this { + //@ts-ignore + return super.on(event, listener); + } + + /** + * This is method produces an event to kafka in asynchrononous mode. It does not wait for success delivery report and resolves on successful adding of + * event to internal producer buffer. The method throws an error on failure which is usually when the queue is full. The successful resolving of this + * method does not guarantee delivery of message to kafka cluster. It is recommended to listen "delivered" event for confirmation and set "acks" setting + * to -1 which is the default setting. + * + * @param {string} key - The key associated with the message. + * @param {object} message - The message object to produce to kafka + * @param {string} topic - The topic name to produce the event to. + * @param {number} partition - To manually set the partition number of the topic to which the event needs to be produced to. + * @param {number} timestamp - To manually set the timestamp (Unix in ms) of the message. + * @param {object} opaque - Per-message opaque pointer that will be provided in the delivery report callback (dr_cb) for referencing this message. + * + * @returns {Promise} - Returns an error if it failed, or true if not + */ + public produceEvent( + key: string, + message: object, + topic?: string, + partition?: number, + timestamp?: number, + opaque?: object + ): Promise { + if (!this.listenerCount("delivery-report")) { + this.on("delivery-report", this.onDeliveryReport.bind(this)); + } + return this.sendToInternalProducer(key, message, topic, partition, timestamp, opaque); + } +} diff --git a/internal/kafka/producer/synchronous_producer.ts b/internal/kafka/producer/synchronous_producer.ts new file mode 100644 index 0000000..c05179d --- /dev/null +++ b/internal/kafka/producer/synchronous_producer.ts @@ -0,0 +1,111 @@ +import { IProducerConfig } from "../../interfaces/producer_config.js"; +import { LibrdKafkaError, DeliveryReport } from "node-rdkafka"; +import { KafkaError } from "../../errors/kafka_error.js"; +import { AbstractProducer } from "./abstract_producer.js"; +import { ICoder } from "../../interfaces/coder.js"; + + +/** + * This class is to be used for producing events in a synchronous mode. + * Each call waits for delivery report of the produced event to kafka before resolving. + * This should be used for scenarios where exactly once semantics is important and speed is compromised. + * If speed is important, then the AsynchronousProducer class must be used as it does not wait for each delivery report before resolving. + * To achieve order guarantee, events must be produced only one at a time. + */ +export class SynchronousProducer extends AbstractProducer { + private deliveryTimeout: number; + + /** + * @param {Coder} serialiser - The Serialiser object to serialise messages before production. + * @param {IProducerConfig} config - ey value pairs to override the default config of the producer client. + */ + constructor( + serialiser: ICoder, + config: IProducerConfig + ) { + const deliveryTimeout = config.deliveryTimeout; + delete config.deliveryTimeout; + + super( + serialiser, + config + ); + + this.deliveryTimeout = deliveryTimeout || 10000; + } + + /** + * @async + * This is method produces an event to kafka in synchrononous mode. Which means it waits for successful delivery report before resolving. + * The method throws an error on failure which is usually when the queue is full or when it cannot retrieve delivery report successfully. + * Resolving of this function is confirmation that message has been successfully delivered to kafka. This method is slower than the produceEventAsynchronously method. + * If using this function for producing events it is recommended that 'acks' in producer config is -1 which is the default value. + * The produce event rejects with an error if delivery report not received within certain timeout.User can re produce the message if + * atleast once semantics is required and it is important to consider that the message may already be produced even with this rejection. + * + * @param {string} key - The key associated with the message. + * @param {object} message - The message object to produce to kafka + * @param {string} topic - The topic name to produce the event to. + * @param {number} partition - To manually set the partition number of the topic to which the event needs to be produced to. + * @param {number} timestamp - To manually set the timestamp (Unix in ms) of the message + * + * @returns {Promise} - Returns an error if it failed, or the delivery report of the delivered message + */ + public async produceEvent( + key: string, + message: object, + topic?: string, + partition?: number, + timestamp?: number + ): Promise { + return new Promise(async (resolve, reject) => { + let deliveryListener: (error: LibrdKafkaError, report: DeliveryReport) => void = () => { }; + try { + const identifier = { time: Date.now() }; + const timer = setTimeout(() => { + reject( + new KafkaError( + "Kafka producer error", + KafkaError.codes.DELIVERY_TIMED_OUT, + false, + `Could not receive delivery confirmation before ${ this.deliveryTimeout} ms`, + "remote" + ) + ); + }, this.deliveryTimeout); + + deliveryListener = (error: LibrdKafkaError, report: DeliveryReport) => { + if (error || (report.opaque === identifier && report.topic === topic)) { + this.removeListener("delivery-report", deliveryListener); + clearTimeout(timer); + if (error) { + reject(KafkaError.convertLibError(error)); + + return; + } + + resolve(report); + return; + } + }; + this.on("delivery-report", deliveryListener); + await this.sendToInternalProducer( + key, + message, + topic, + partition, + timestamp, + identifier + ); + + setTimeout(() => { + this.poll(); + }, 100); + } catch (error) { + this.removeListener("delivery-report", deliveryListener); + + throw KafkaError.createUnknown(error); + } + }); + } +} diff --git a/internal/logger/logger.ts b/internal/logger/logger.ts new file mode 100644 index 0000000..938fa0c --- /dev/null +++ b/internal/logger/logger.ts @@ -0,0 +1,141 @@ +import winston, { Logger as WinstonLogger } from "winston"; +import { LoggerConfig } from "../interfaces/logger_config.js"; +import SentryImport from "winston-transport-sentry-node"; +const Sentry = SentryImport.default; + +let logger: WinstonLogger | null = null; + +/** + * LoggerClass that maintains a singleton, and has straightforward methods to log any application events. + * + * @author - Vibhu Rajeev, Keshav Gupta - Polygon Technology + */ +export class Logger { + /** + * @static + * Create method must first be called before using the logger. It creates a singleton, which will then + * be referred to throughout the application. + * + * @param {LoggerConfig} config - Logger configuration to overwrite winston configs and define sentry + datadog endpoints. + */ + static create(config: LoggerConfig) { + if (!logger) { + logger = winston.createLogger(Object.assign({ + format: winston.format.combine( + winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }), + winston.format.colorize({ + all: true, + colors: { + error: "red", + warn: "yellow", + info: "green", + debug: "white", + } + }), + winston.format.printf( + (info: any) => `${info.timestamp} ${info.level}: ${info.message}`, + ), + ), + transports: [ + new winston.transports.Console({ + level: config.console?.level || "info" + }), + new Sentry( + { + sentry: { + dsn: config.sentry?.dsn, + environment: config.sentry?.environment || "development" + }, + level: config.sentry?.level || "error", + } + ), + new winston.transports.Http( + { + host: "http-intake.logs.datadoghq.com", + path: "/api/v2/logs?dd-api-key=" + config.datadog?.api_key + "&ddsource=nodejs&service=" + config.datadog?.service_name, + ssl: true + } + ), + ] + }, + config.winston + )); + } + } + + /** + * @static + * Method to log for level - "info", this should not be called if it has been custom levels are + * set which does not include "info" + * + * @param {string|object} message - String or object to log. + */ + static info(message: string | object): void { + if (typeof message === "string") { + logger?.info(message); + } else { + logger?.info(JSON.stringify(message)); + } + } + + /** + * @static + * Method to log for level - "debug", this should not be called if it has been custom levels are + * set which does not include "debug" + * + * @param {string|object} message - String or object to log. + */ + static debug(message: string | object): void { + if (typeof message === "string") { + logger?.debug(message); + } else { + logger?.debug(JSON.stringify(message)); + } + } + + /** + * @static + * Method to log for level - "error", this should not be called if it has been custom levels are + * set which does not include "error" + * + * @param {string|object} error - String or object to log. + */ + static error(error: string | object): void { + if (typeof error === "string") { + logger?.error(error); + } else { + logger?.error( + `${(error as Error).message ? `${(error as Error).message} : ` : ""}${JSON.stringify(error)}` + ); + } + } + + /** + * @static + * Method to log for level - "warn", this should not be called if it has been custom levels are + * set which does not include "warn" + * + * @param {string|object} message - String or object to log. + */ + static warn(message: string | object): void { + if (typeof message === "string") { + logger?.warn(message); + } else { + logger?.warn(JSON.stringify(message)); + } + } + + /** + * @static + * Method to log for any level, which should be used to log all custom levels that may be added. + * + * @param {string|object} message - String or object to log. + */ + static log(level: string, message: string | object): void { + if (typeof message === "string") { + logger?.log(level, message); + } else { + logger?.log(level, JSON.stringify(message)); + } + } +} diff --git a/internal/mongo/database.ts b/internal/mongo/database.ts new file mode 100644 index 0000000..6d670a7 --- /dev/null +++ b/internal/mongo/database.ts @@ -0,0 +1,78 @@ +import { Mongoose, Schema, CompileModelOptions } from "mongoose"; + +let database: Database | null = null; + +/** + * Database class is a singleton class that provides simple straightforward method to connect and disconnect to database + * with a particular collection. it has one inconsistency on not extending this class from mongoose due to mongoose implementation. + * that is why mongoose is initialized in the constructor. + */ +export class Database { + private database!: Mongoose; + + /** + * @param {string} url - The url for database that needs to be connected + * this constructor will create instance of database and initialize it with database URL + */ + constructor(private url: string) { + if (!database) { + this.database = new Mongoose(); + database = this; + } + + return database; + } + + /** + * The method connect will connect to database and will return if already connnected to db. It is an async function + * to handle errors in better ways. It has a void return type. this function should only be called once when + * the class is initialized. there is no harm in calling the function again as it will return if its already + * connected to database + * + * @returns {Promis} + */ + public async connect(): Promise { + if (this.database.connection.readyState === 1 || this.database.connection.readyState === 2) { + return true; + } + + await this.database.connect(this.url); + return true; + } + + /** + * it will disconnect from database if database is connected. and has a void return type. It is internally + * calling disconnect function of Mongoose. this function should only be called when database needs to be disconnected. + * + * @returns {Promise} + */ + public async disconnect(): Promise { + if (this.database.connection.readyState === 0 || this.database.connection.readyState === 3) { + return true; + } + + await this.database.disconnect(); + + return true; + } + + /** + * Defines a model or retrieves it. + * Models defined on this mongoose instance are available to all connection created by the same mongoose instance. + * + * @param {string} name - Name of the model. + * @param {Schema} schema - Schema for which model is to be created. + * @param {string} collection - Collection name of the model. + * @param {CompileModelOptions} options - Optional object for mongoose options while creating the collection. + * + * @returns {U} - The mongoose model. + */ + public model( + name: string, + schema?: Schema, + collection?: string, + options?: CompileModelOptions + ): U { + return this.database.model(name, schema, collection, options); + } +} diff --git a/internal/queue/queue.ts b/internal/queue/queue.ts new file mode 100644 index 0000000..8ef3c5e --- /dev/null +++ b/internal/queue/queue.ts @@ -0,0 +1,71 @@ +/** + * A simple class that offers methods to create internal buffers and maintain them. + */ +export class Queue { + private items: Array | T> = []; + + /** + * Public method to add an item to the queue. This class only maintains one queue and hence it is important to be careful + * while queueing different entities on the same instance un intentionally. + * + * @param {Promise | T} item - Item to be added to the queue + * + * @returns {void} + */ + public enqueue(item: Promise | T): void { + this.items.push(item); + } + + /** + * Returns an item from the beginning(added first) of the queue and removes it from the queue. Returns null if the queue is empty. + * + * @returns {Promise | T | null} - The removed the item. + */ + public shift(): Promise | T | null { + if (this.isEmpty()) { + return null; + } + + return this.items.shift() as Promise | T; + } + + /** + * Returns the first item from the queue without removing it. + * + * @returns {Promise | T | null} - The first item in the queue or null if empty. + */ + public front(): Promise | T | null { + if (this.isEmpty()) { + return null; + } + + return this.items[0]; + } + + /** + * Method to check if the queue is empty + * + * @returns {boolean} - Returns true if empty and false otherwise. + */ + public isEmpty(): boolean { + return this.getLength() == 0; + } + + /** + * Method to find the length of the queue. + * + * @returns {number} - The length of the queue. + */ + public getLength(): number { + return this.items.length; + } + + /** + * Removes all the items from the queue. + * + * @returns {number} - The queue length after clearing. + */ + public clear(): number { + return this.items.length = 0; + } +} diff --git a/internal/rpc/json_rpc_client.ts b/internal/rpc/json_rpc_client.ts new file mode 100644 index 0000000..c64fda9 --- /dev/null +++ b/internal/rpc/json_rpc_client.ts @@ -0,0 +1,38 @@ +import { IRPCPayload } from "../interfaces/rpc_payload.js"; +import axios from "axios"; + +/** + * A utility class to make RPC calls to the given node URL. + */ +export class JSONRPCClient { + + /** + * @constructor + * + * @param {string} url - The url of the node to make RPC call. + */ + constructor( + private url: string + ) {} + + /** + * Method to make an rpc call + * + * @param {IRPCPayload} payload + * + * @returns {Promise} + */ + public async call(payload: IRPCPayload): Promise { + const response = await axios.post( + this.url, + { + jsonrpc: "2.0", + id: new Date().getTime(), + method: payload.method, + params: payload.params ?? [] + } + ); + + return response.data.result; + } +} diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..d02e9ce --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,22 @@ +import { JestConfigWithTsJest } from "ts-jest"; + +const jestConfig: JestConfigWithTsJest = { + "transform": { + "^.+\\.(j|t)s?$": "babel-jest" + }, + extensionsToTreatAsEsm: ['.ts'], + clearMocks: true, + coverageThreshold: { + global: { + "branches": 80, + "functions": 80, + "lines": 80, + "statements": 80 + }, + }, + coveragePathIgnorePatterns: [ + "/internal/block_producers/produced_blocks_model" + ] +} + +export default jestConfig diff --git a/public/block_producers/block_polling_producer.ts b/public/block_producers/block_polling_producer.ts new file mode 100644 index 0000000..b310470 --- /dev/null +++ b/public/block_producers/block_polling_producer.ts @@ -0,0 +1,69 @@ +import { IProducedBlock, ProducedBlocksModel, IProducedBlocksModel } from "@internal/block_producers/produced_blocks_model.js"; +import { IBlockProducerConfig } from "@internal/interfaces/block_producer_config.js"; +import { IProducerConfig } from "@internal/interfaces/producer_config.js"; +import { BlockGetter } from "@internal/block_getters/block_getter.js"; +import { Coder } from "@internal/coder/protobuf_coder.js"; +import { BlockPoller } from "@internal/block_subscription/block_polling.js"; +import { Database } from "@internal/mongo/database.js"; +import { BlockProducer } from "@internal/block_producers/block_producer.js"; +import Eth from "web3-eth"; + +/** + * Block Poller producer class which retrieves block from polling every block + * for producing to kafka. + * + */ +export class BlockPollerProducer extends BlockProducer { + /** + * @constructor + * + * @param {IBlockProducerConfig} config + * + * @returns {BlockPollerProducer} + */ + constructor(config: IBlockProducerConfig) { + const endpoint = config.rpcWsEndpoints?.[0] || ""; + const startBlock = config.startBlock || 0; + const mongoUrl = config.mongoUrl || "mongodb://localhost:27017/open-api"; + const blockPollingTimeout = config.blockPollingTimeout || 2000; + const maxRetries = config.maxRetries || 0; + const maxReOrgDepth = config.maxReOrgDepth || 0; + + delete config.rpcWsEndpoints; + delete config.startBlock; + delete config.mongoUrl; + delete config.maxReOrgDepth; + delete config.maxRetries; + delete config.blockPollingTimeout; + + const database = new Database(mongoUrl); + + const blockGetter = new BlockGetter( + //@ts-ignore + new Eth(endpoint), + maxRetries + ); + + super( + new Coder( + "block", + "blockpackage", + "Block" + ), + config as IProducerConfig, + new BlockPoller( + blockGetter, + blockPollingTimeout + ), + blockGetter, + database, + database.model>( + "ProducedBlocks", + ProducedBlocksModel, + "producedblocks" + ), + startBlock, + maxReOrgDepth + ); + } +} diff --git a/public/block_producers/erigon_block_producer.ts b/public/block_producers/erigon_block_producer.ts new file mode 100644 index 0000000..33f0d76 --- /dev/null +++ b/public/block_producers/erigon_block_producer.ts @@ -0,0 +1,82 @@ +import { IProducedBlock, ProducedBlocksModel, IProducedBlocksModel } from "@internal/block_producers/produced_blocks_model.js"; +import { BlockSubscription } from "@internal/block_subscription/block_subscription.js"; +import { IBlockProducerConfig } from "@internal/interfaces/block_producer_config.js"; +import { IProducerConfig } from "@internal/interfaces/producer_config.js"; +import { BlockGetter } from "@internal/block_getters/block_getter.js"; +import { Coder } from "@internal/coder/protobuf_coder.js"; +import { Database } from "@internal/mongo/database.js"; +import Eth from "web3-eth"; +import { BlockProducer } from "@internal/block_producers/block_producer.js"; + +/** + * Erigon block producer class which retrieves block from erigon node + * for producing to kafka. + * + * @author - Vibhu Rajeev + */ +export class ErigonBlockProducer extends BlockProducer { + /** + * @constructor + * + * @param {IBlockProducerConfig} config + * + * @returns {ErigonBlockProducer} + */ + constructor(config: IBlockProducerConfig) { + const endpoints = config.rpcWsEndpoints || []; + const startBlock = config.startBlock || 0; + const mongoUrl = config.mongoUrl || "mongodb://localhost:27017/open-api"; + const maxReOrgDepth = config.maxReOrgDepth || 0; + const maxRetries = config.maxRetries || 0; + const blockSubscriptionTimeout = config.blockSubscriptionTimeout; + + // Has to be done or Kafka complains later + delete config.rpcWsEndpoints; + delete config.startBlock; + delete config.mongoUrl; + delete config.maxReOrgDepth; + delete config.maxRetries; + delete config.blockSubscriptionTimeout; + + const database = new Database(mongoUrl); + + //@ts-ignore + const eth = new Eth( + //@ts-ignore + new Eth.providers.WebsocketProvider( + endpoints[0], + { + reconnect: { + auto: true + }, + clientConfig: { + maxReceivedFrameSize: 1000000000, + maxReceivedMessageSize: 1000000000, + } + } + ) + ); + + super( + new Coder("block", "blockpackage", "Block"), + config as IProducerConfig, + new BlockSubscription( + //@ts-ignore + eth, + endpoints, + maxRetries, + "erigon_block_getter", + blockSubscriptionTimeout + ), + new BlockGetter(eth, maxRetries), + database, + database.model>( + "ProducedBlocks", + ProducedBlocksModel, + "producedblocks" + ), + startBlock, + maxReOrgDepth + ); + } +} diff --git a/public/block_producers/produce_blocks.ts b/public/block_producers/produce_blocks.ts new file mode 100644 index 0000000..c50da0e --- /dev/null +++ b/public/block_producers/produce_blocks.ts @@ -0,0 +1,30 @@ +import { BlockPollerProducer } from "./block_polling_producer.js"; +import { QuickNodeBlockProducer } from "./quicknode_block_producer.js"; +import { ErigonBlockProducer } from "./erigon_block_producer.js"; +import { BlockProducer } from "@internal/block_producers/block_producer.js"; +import { IBlockProducerConfig } from "@internal/interfaces/block_producer_config.js"; + +function getProducer( + config: IBlockProducerConfig +): BlockProducer { + const type = config.type; + delete config.type; + + if (type === "quicknode") { + return new QuickNodeBlockProducer(config); + } + + if (type === "erigon") { + return new ErigonBlockProducer(config); + } + + return new BlockPollerProducer(config); +} + +export function produceBlocks( + config: IBlockProducerConfig +): BlockProducer { + const producer = getProducer(config); + producer.start(); + return producer +} diff --git a/public/block_producers/quicknode_block_producer.ts b/public/block_producers/quicknode_block_producer.ts new file mode 100644 index 0000000..f4dbca9 --- /dev/null +++ b/public/block_producers/quicknode_block_producer.ts @@ -0,0 +1,84 @@ +import { BlockProducer } from "@internal/block_producers/block_producer.js"; +import { IProducedBlock, ProducedBlocksModel, IProducedBlocksModel } from "@internal/block_producers/produced_blocks_model.js"; +import { BlockSubscription } from "@internal/block_subscription/block_subscription.js"; +import { IBlockProducerConfig } from "@internal/interfaces/block_producer_config.js"; +import { IProducerConfig } from "@internal/interfaces/producer_config.js"; +import { BlockGetter } from "@internal/block_getters/block_getter.js"; +import { Coder } from "@internal/coder/protobuf_coder.js"; +import { Database } from "@internal/mongo/database.js"; +import Eth from "web3-eth"; + +/** + * Quicknode block producer class which retrieves block from quick node + * for producing to kafka. + * + */ +export class QuickNodeBlockProducer extends BlockProducer { + + /** + * @constructor + * + * @param {IBlockProducerConfig} config + * + * @returns {QuickNodeBlockProducer} + */ + constructor(config: IBlockProducerConfig) { + + const endpoints = config.rpcWsEndpoints || []; + const startBlock = config.startBlock || 0; + const mongoUrl = config.mongoUrl || "mongodb://localhost:27017/open-api"; + const maxReOrgDepth = config.maxReOrgDepth || 0; + const maxRetries = config.maxRetries || 0; + const blockSubscriptionTimeout = config.blockSubscriptionTimeout; + + // Has to be done or Kafka complains later + delete config.rpcWsEndpoints; + delete config.startBlock; + delete config.mongoUrl; + delete config.maxReOrgDepth; + delete config.maxRetries; + delete config.blockSubscriptionTimeout; + + //@ts-ignore + const eth = new Eth( + //@ts-ignore + new Eth.providers.WebsocketProvider( + endpoints[0], + { + reconnect: { + auto: true + }, + clientConfig: { + maxReceivedFrameSize: 1000000000, + maxReceivedMessageSize: 1000000000, + } + } + ) + ); + + const database = new Database(mongoUrl); + + super( + new Coder("block", "blockpackage", "Block"), + config as IProducerConfig, + new BlockSubscription( + //@ts-ignore + eth, + endpoints, + maxRetries, + "quicknode_block_getter", + blockSubscriptionTimeout + ), + new BlockGetter(eth, maxRetries), + database, + database.model>( + "ProducedBlocks", + ProducedBlocksModel, + "producedblocks" + ), + startBlock, + maxReOrgDepth + ); + + } +} diff --git a/public/coder/abi_coder.ts b/public/coder/abi_coder.ts new file mode 100644 index 0000000..9745c12 --- /dev/null +++ b/public/coder/abi_coder.ts @@ -0,0 +1 @@ +export * from "@internal/coder/abi_coder.js"; diff --git a/public/coder/protobuf_coder.ts b/public/coder/protobuf_coder.ts new file mode 100644 index 0000000..49d47e0 --- /dev/null +++ b/public/coder/protobuf_coder.ts @@ -0,0 +1 @@ +export * from "@internal/coder/protobuf_coder.js"; diff --git a/public/data_transformation/asynchronous_data_transformer.ts b/public/data_transformation/asynchronous_data_transformer.ts new file mode 100644 index 0000000..3108045 --- /dev/null +++ b/public/data_transformation/asynchronous_data_transformer.ts @@ -0,0 +1,18 @@ +import { AsynchronousConsumer } from "@internal/kafka/consumer/asynchronous_consumer.js"; +import { AsynchronousProducer } from "@internal/kafka/producer/asynchronous_producer.js"; +import { AbstractDataTransformer } from "@internal/data_transformation/abstract_data_transformer.js"; + +/** + * Concurrent Data transformer transforms the data concurrently and doesn't for the transformed data to produce before + * transforming data further. Services needs to implement their own transform method + */ +export abstract class AsynchronousDataTransformer extends AbstractDataTransformer { + /** + * @param {AsynchronousConsumer} consumer - ConcurrentConsumer instance to consume data + * @param {AsynchronousProducer} producer - producer instance to produce transformed data + */ + constructor(consumer: AsynchronousConsumer, producer: AsynchronousProducer) + { + super(consumer, producer); + } +} diff --git a/public/data_transformation/synchronous_data_transformer.ts b/public/data_transformation/synchronous_data_transformer.ts new file mode 100644 index 0000000..06647ab --- /dev/null +++ b/public/data_transformation/synchronous_data_transformer.ts @@ -0,0 +1,18 @@ +import { SynchronousConsumer } from "@internal/kafka/consumer/synchronous_consumer.js"; +import { AsynchronousProducer } from "@internal/kafka/producer/asynchronous_producer.js"; +import { AbstractDataTransformer } from "@internal/data_transformation/abstract_data_transformer.js"; + +/** + * SynchronousDataTransformer transforms the data sequentially and waits for the transformed data to produce before + * transforming data further. Services needs to implement their own transform method + */ +export abstract class SynchronousDataTransformer extends AbstractDataTransformer { + /** + * @param {SynchronousConsumer} consumer - Sequential consumer instance to produce raw data + * @param {AsynchronousProducer} producer - Async producer instance to produce transformed data + */ + constructor(consumer: SynchronousConsumer, producer: AsynchronousProducer) + { + super(consumer, producer); + } +} diff --git a/public/enums/bridgetype.ts b/public/enums/bridgetype.ts new file mode 100644 index 0000000..e13ece1 --- /dev/null +++ b/public/enums/bridgetype.ts @@ -0,0 +1 @@ +export * from "@internal/enums/bridgetype.js"; diff --git a/public/enums/tokentype.ts b/public/enums/tokentype.ts new file mode 100644 index 0000000..a3ba932 --- /dev/null +++ b/public/enums/tokentype.ts @@ -0,0 +1 @@ +export * from "@internal/enums/tokentype.js"; diff --git a/public/errors/api_error.ts b/public/errors/api_error.ts new file mode 100644 index 0000000..d982d74 --- /dev/null +++ b/public/errors/api_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/api_error.js"; diff --git a/public/errors/base_error.ts b/public/errors/base_error.ts new file mode 100644 index 0000000..cff6562 --- /dev/null +++ b/public/errors/base_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/base_error.js"; diff --git a/public/errors/block_producer_error.ts b/public/errors/block_producer_error.ts new file mode 100644 index 0000000..c6d0c45 --- /dev/null +++ b/public/errors/block_producer_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/block_producer_error.js"; diff --git a/public/errors/coder_error.ts b/public/errors/coder_error.ts new file mode 100644 index 0000000..efcdef6 --- /dev/null +++ b/public/errors/coder_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/coder_error.js"; diff --git a/public/errors/create_error_object.ts b/public/errors/create_error_object.ts new file mode 100644 index 0000000..7ebce70 --- /dev/null +++ b/public/errors/create_error_object.ts @@ -0,0 +1 @@ +export * from "@internal/errors/create_error_object.js"; diff --git a/public/errors/error_codes.ts b/public/errors/error_codes.ts new file mode 100644 index 0000000..4f14acf --- /dev/null +++ b/public/errors/error_codes.ts @@ -0,0 +1 @@ +export * from "@internal/errors/error_codes.js"; diff --git a/public/errors/event_consumer_error.ts b/public/errors/event_consumer_error.ts new file mode 100644 index 0000000..e41639f --- /dev/null +++ b/public/errors/event_consumer_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/event_consumer_error.js"; diff --git a/public/errors/get_error_message.ts b/public/errors/get_error_message.ts new file mode 100644 index 0000000..5289781 --- /dev/null +++ b/public/errors/get_error_message.ts @@ -0,0 +1 @@ +export * from "@internal/errors/get_error_message.js"; diff --git a/public/errors/index.ts b/public/errors/index.ts new file mode 100644 index 0000000..64e416a --- /dev/null +++ b/public/errors/index.ts @@ -0,0 +1,9 @@ +export * from "@internal/errors/block_producer_error.js"; +export * from "@internal/errors/coder_error.js"; +export * from "@internal/errors/create_error_object.js"; +export * from "@internal/errors/error_codes.js"; +export * from "@internal/errors/event_consumer_error.js"; +export * from "@internal/errors/get_error_message.js"; +export * from "@internal/errors/is_base_error.js"; +export * from "@internal/errors/is_librdkafka_error.js"; +export * from "@internal/errors/kafka_error.js"; diff --git a/public/errors/is_base_error.ts b/public/errors/is_base_error.ts new file mode 100644 index 0000000..aeef531 --- /dev/null +++ b/public/errors/is_base_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/is_base_error.js"; diff --git a/public/errors/is_librdkafka_error.ts b/public/errors/is_librdkafka_error.ts new file mode 100644 index 0000000..4d47400 --- /dev/null +++ b/public/errors/is_librdkafka_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/is_librdkafka_error.js"; diff --git a/public/errors/kafka_error.ts b/public/errors/kafka_error.ts new file mode 100644 index 0000000..8961429 --- /dev/null +++ b/public/errors/kafka_error.ts @@ -0,0 +1 @@ +export * from "@internal/errors/kafka_error.js"; diff --git a/public/event_consumer/abstract_event_consumer.ts b/public/event_consumer/abstract_event_consumer.ts new file mode 100644 index 0000000..33a50c9 --- /dev/null +++ b/public/event_consumer/abstract_event_consumer.ts @@ -0,0 +1 @@ +export * from "@internal/event_consumer/abstract_event_consumer.js"; diff --git a/public/filter/bloom_filter.ts b/public/filter/bloom_filter.ts new file mode 100644 index 0000000..b8df61e --- /dev/null +++ b/public/filter/bloom_filter.ts @@ -0,0 +1 @@ +export * from "@internal/filter/bloom_filter.js"; diff --git a/public/index.ts b/public/index.ts new file mode 100644 index 0000000..6a8c476 --- /dev/null +++ b/public/index.ts @@ -0,0 +1,56 @@ +// block_producer +export * from "./block_producers/produce_blocks.js"; +export * from "./block_producers/block_polling_producer.js"; +export * from "./block_producers/erigon_block_producer.js"; +export * from "./block_producers/quicknode_block_producer.js"; + +// coder +export * from "./coder/abi_coder.js"; +export * from "./coder/protobuf_coder.js"; + +// data transformation +export * from "./data_transformation/asynchronous_data_transformer.js"; +export * from "./data_transformation/synchronous_data_transformer.js"; + +// Enums +export * from "./enums/bridgetype.js"; +export * from "./enums/tokentype.js"; + +// Errors +export * from "./errors/api_error.js" +export * from "./errors/base_error.js" +export * from "./errors/block_producer_error.js"; +export * from "./errors/coder_error.js"; +export * from "./errors/create_error_object.js"; +export * from "./errors/error_codes.js"; +export * from "./errors/event_consumer_error.js"; +export * from "./errors/get_error_message.js"; +export * from "./errors/is_base_error.js"; +export * from "./errors/is_librdkafka_error.js"; +export * from "./errors/kafka_error.js"; + +//Event Consumer +export * from "./event_consumer/abstract_event_consumer.js"; + +// Bloom Filter +export * from "./filter/bloom_filter.js"; + +// Interfaces +export * from "./interfaces/index.js"; + +// kafka +export * from "./kafka/consumer/consume.js"; +export * from "./kafka/consumer/asynchronous_consumer.js"; +export * from "./kafka/consumer/synchronous_consumer.js"; +export * from "./kafka/producer/produce.js"; +export * from "./kafka/producer/asynchronous_producer.js"; +export * from "./kafka/producer/synchronous_producer.js"; + +// logger +export * from "./logger/logger.js"; + +// MongoDB +export * from "./mongo/database.js"; + +// rpc +export * from "./rpc/json_rpc_client.js" diff --git a/public/interfaces/async_observer.ts b/public/interfaces/async_observer.ts new file mode 100644 index 0000000..168cbc5 --- /dev/null +++ b/public/interfaces/async_observer.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/async_observer.js"; diff --git a/public/interfaces/block.ts b/public/interfaces/block.ts new file mode 100644 index 0000000..f6d828b --- /dev/null +++ b/public/interfaces/block.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/block.js"; diff --git a/public/interfaces/block_getter.ts b/public/interfaces/block_getter.ts new file mode 100644 index 0000000..72b4017 --- /dev/null +++ b/public/interfaces/block_getter.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/block_getter.js"; diff --git a/public/interfaces/block_getter_worker_promise.ts b/public/interfaces/block_getter_worker_promise.ts new file mode 100644 index 0000000..3e682b3 --- /dev/null +++ b/public/interfaces/block_getter_worker_promise.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/block_getter_worker_promise.js"; diff --git a/public/interfaces/block_header.ts b/public/interfaces/block_header.ts new file mode 100644 index 0000000..104b754 --- /dev/null +++ b/public/interfaces/block_header.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/block_header.js"; diff --git a/public/interfaces/block_producer_config.ts b/public/interfaces/block_producer_config.ts new file mode 100644 index 0000000..27050e3 --- /dev/null +++ b/public/interfaces/block_producer_config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/block_producer_config.js"; diff --git a/public/interfaces/block_subscription.ts b/public/interfaces/block_subscription.ts new file mode 100644 index 0000000..7493de0 --- /dev/null +++ b/public/interfaces/block_subscription.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/block_subscription.js"; diff --git a/public/interfaces/block_worker_message.ts b/public/interfaces/block_worker_message.ts new file mode 100644 index 0000000..dd54901 --- /dev/null +++ b/public/interfaces/block_worker_message.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/block_worker_message.js"; diff --git a/public/interfaces/coder.ts b/public/interfaces/coder.ts new file mode 100644 index 0000000..65bfea1 --- /dev/null +++ b/public/interfaces/coder.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/coder.js"; diff --git a/public/interfaces/coder_config.ts b/public/interfaces/coder_config.ts new file mode 100644 index 0000000..0317eee --- /dev/null +++ b/public/interfaces/coder_config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/coder_config.js"; diff --git a/public/interfaces/common_kafka_events.ts b/public/interfaces/common_kafka_events.ts new file mode 100644 index 0000000..08087d9 --- /dev/null +++ b/public/interfaces/common_kafka_events.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/common_kafka_events.js"; diff --git a/public/interfaces/config.ts b/public/interfaces/config.ts new file mode 100644 index 0000000..abc1500 --- /dev/null +++ b/public/interfaces/config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/config.js"; diff --git a/public/interfaces/consumer_config.ts b/public/interfaces/consumer_config.ts new file mode 100644 index 0000000..9d913e2 --- /dev/null +++ b/public/interfaces/consumer_config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/consumer_config.js"; diff --git a/public/interfaces/consumer_queue_object.ts b/public/interfaces/consumer_queue_object.ts new file mode 100644 index 0000000..b26b745 --- /dev/null +++ b/public/interfaces/consumer_queue_object.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/consumer_queue_object.js"; diff --git a/public/interfaces/deposit.ts b/public/interfaces/deposit.ts new file mode 100644 index 0000000..3819998 --- /dev/null +++ b/public/interfaces/deposit.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/deposit.js"; diff --git a/public/interfaces/deserialised_kafka_message.ts b/public/interfaces/deserialised_kafka_message.ts new file mode 100644 index 0000000..1d45711 --- /dev/null +++ b/public/interfaces/deserialised_kafka_message.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/deserialised_kafka_message.js"; diff --git a/public/interfaces/event_log.ts b/public/interfaces/event_log.ts new file mode 100644 index 0000000..8399bcb --- /dev/null +++ b/public/interfaces/event_log.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/event_log.js"; diff --git a/public/interfaces/index.ts b/public/interfaces/index.ts new file mode 100644 index 0000000..c071d2d --- /dev/null +++ b/public/interfaces/index.ts @@ -0,0 +1,36 @@ +export * from "./async_observer.js"; +export * from "./block_getter_worker_promise.js"; +export * from "./block_getter.js"; +export * from "./block_header.js"; +export * from "./block_producer_config.js"; +export * from "./block_subscription.js"; +export * from "./block_worker_message.js"; +export * from "./block.js"; +export * from "./coder_config.js"; +export * from "./coder.js"; +export * from "./common_kafka_events.js"; +export * from "./config.js"; +export * from "./consumer_config.js"; +export * from "./consumer_queue_object.js"; +export * from "./deposit.js"; +export * from "./deserialised_kafka_message.js"; +export * from "./event_log.js"; +export * from "./kafka_coder_config.js"; +export * from "./logger_config.js"; +export * from "./mapper.js"; +export * from "./new_heads_subscriber.js"; +export * from "./observer.js"; +export * from "./producer_config.js"; +export * from "./quicknode_response.js"; +export * from "./raw_block.js"; +export * from "./raw_receipt.js"; +export * from "./raw_transaction.js"; +export * from "./rpc_payload.js"; +export * from "./sequential_consumer_config.js"; +export * from "./stream_api_block.js"; +export * from "./synchronous_producer.js"; +export * from "./transaction_receipt.js"; +export * from "./transaction.js"; +export * from "./transformed_block.js"; +export * from "./web3_transaction_receipt.js"; +export * from "./web3_transaction.js"; diff --git a/public/interfaces/kafka_coder_config.ts b/public/interfaces/kafka_coder_config.ts new file mode 100644 index 0000000..278b046 --- /dev/null +++ b/public/interfaces/kafka_coder_config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/kafka_coder_config.js"; diff --git a/public/interfaces/logger_config.ts b/public/interfaces/logger_config.ts new file mode 100644 index 0000000..30b48c5 --- /dev/null +++ b/public/interfaces/logger_config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/logger_config.js"; diff --git a/public/interfaces/mapper.ts b/public/interfaces/mapper.ts new file mode 100644 index 0000000..5f9aa11 --- /dev/null +++ b/public/interfaces/mapper.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/mapper.js"; diff --git a/public/interfaces/new_heads_subscriber.ts b/public/interfaces/new_heads_subscriber.ts new file mode 100644 index 0000000..5752db3 --- /dev/null +++ b/public/interfaces/new_heads_subscriber.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/new_heads_subscriber.js"; diff --git a/public/interfaces/observer.ts b/public/interfaces/observer.ts new file mode 100644 index 0000000..a976020 --- /dev/null +++ b/public/interfaces/observer.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/observer.js"; diff --git a/public/interfaces/producer_config.ts b/public/interfaces/producer_config.ts new file mode 100644 index 0000000..5003013 --- /dev/null +++ b/public/interfaces/producer_config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/producer_config.js"; diff --git a/public/interfaces/quicknode_response.ts b/public/interfaces/quicknode_response.ts new file mode 100644 index 0000000..7ab3a39 --- /dev/null +++ b/public/interfaces/quicknode_response.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/quicknode_response.js"; diff --git a/public/interfaces/raw_block.ts b/public/interfaces/raw_block.ts new file mode 100644 index 0000000..ecbbdc5 --- /dev/null +++ b/public/interfaces/raw_block.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/raw_block.js"; diff --git a/public/interfaces/raw_receipt.ts b/public/interfaces/raw_receipt.ts new file mode 100644 index 0000000..607c249 --- /dev/null +++ b/public/interfaces/raw_receipt.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/raw_receipt.js"; diff --git a/public/interfaces/raw_transaction.ts b/public/interfaces/raw_transaction.ts new file mode 100644 index 0000000..65c07d2 --- /dev/null +++ b/public/interfaces/raw_transaction.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/raw_transaction.js"; diff --git a/public/interfaces/rpc_payload.ts b/public/interfaces/rpc_payload.ts new file mode 100644 index 0000000..912ae18 --- /dev/null +++ b/public/interfaces/rpc_payload.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/rpc_payload.js"; diff --git a/public/interfaces/sequential_consumer_config.ts b/public/interfaces/sequential_consumer_config.ts new file mode 100644 index 0000000..6daa95f --- /dev/null +++ b/public/interfaces/sequential_consumer_config.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/sequential_consumer_config.js"; diff --git a/public/interfaces/stream_api_block.ts b/public/interfaces/stream_api_block.ts new file mode 100644 index 0000000..8df0615 --- /dev/null +++ b/public/interfaces/stream_api_block.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/stream_api_block.js"; diff --git a/public/interfaces/synchronous_producer.ts b/public/interfaces/synchronous_producer.ts new file mode 100644 index 0000000..6a45229 --- /dev/null +++ b/public/interfaces/synchronous_producer.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/synchronous_producer.js"; diff --git a/public/interfaces/transaction.ts b/public/interfaces/transaction.ts new file mode 100644 index 0000000..41b281c --- /dev/null +++ b/public/interfaces/transaction.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/transaction.js"; diff --git a/public/interfaces/transaction_receipt.ts b/public/interfaces/transaction_receipt.ts new file mode 100644 index 0000000..ea9441b --- /dev/null +++ b/public/interfaces/transaction_receipt.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/transaction_receipt.js"; diff --git a/public/interfaces/transformed_block.ts b/public/interfaces/transformed_block.ts new file mode 100644 index 0000000..24a4d2f --- /dev/null +++ b/public/interfaces/transformed_block.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/transformed_block.js"; diff --git a/public/interfaces/web3_transaction.ts b/public/interfaces/web3_transaction.ts new file mode 100644 index 0000000..8276a11 --- /dev/null +++ b/public/interfaces/web3_transaction.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/web3_transaction.js"; diff --git a/public/interfaces/web3_transaction_receipt.ts b/public/interfaces/web3_transaction_receipt.ts new file mode 100644 index 0000000..8be2113 --- /dev/null +++ b/public/interfaces/web3_transaction_receipt.ts @@ -0,0 +1 @@ +export * from "@internal/interfaces/web3_transaction_receipt.js"; diff --git a/public/kafka/consumer/asynchronous_consumer.ts b/public/kafka/consumer/asynchronous_consumer.ts new file mode 100644 index 0000000..45bf96d --- /dev/null +++ b/public/kafka/consumer/asynchronous_consumer.ts @@ -0,0 +1 @@ +export * from "@internal/kafka/consumer/asynchronous_consumer.js"; diff --git a/public/kafka/consumer/consume.ts b/public/kafka/consumer/consume.ts new file mode 100644 index 0000000..0166d65 --- /dev/null +++ b/public/kafka/consumer/consume.ts @@ -0,0 +1,68 @@ +import { IConsumerConfig } from "@internal/interfaces/consumer_config.js"; +import { SynchronousConsumer } from "@internal/kafka/consumer/synchronous_consumer.js"; +import { AsynchronousConsumer } from "@internal/kafka/consumer/asynchronous_consumer.js"; +import { Coder } from "@internal/coder/protobuf_coder.js"; +import { IObserver } from "@internal/interfaces/observer.js"; +import { DeserialisedMessage } from "public/index.js"; +import { BaseError } from "@internal/errors/base_error.js"; + +/** + * Function to be used as functional implementation for the consumer classes for asynchronous + * and synchronous consumer. this function will create coder class if protobuf coder is required. + * type and coder can be passed if coder other that protobuf coder is needed. + * + * @param {IConsumerConfig} config - consumer config + * + * @returns {AsynchronousConsumer | SynchronousConsumer} + */ +export function consume( + config: IConsumerConfig, observer: IObserver +): AsynchronousConsumer | SynchronousConsumer { + const topic = config.topic; + let coders = config.coders; + const type = config.type; + const coderConfig = config.coderConfig; + const encoding = config.encoding; + delete config.topic; + delete config.coders; + delete config.type; + delete config.coderConfig; + delete config.encoding; + + if (!encoding || encoding === 'protobuf') { + if (!coderConfig || !topic) { + throw new Error("Please provide coder config or topic"); + } + coders = {}; + if (Array.isArray(topic) && Array.isArray(coderConfig)) { + for (let topicIndex = 0; topicIndex < topic.length; topicIndex++) { + coders[topic[topicIndex]] = new Coder(coderConfig[topicIndex].fileName, coderConfig[topicIndex].packageName, coderConfig[topicIndex].messageType); + } + } else if (!Array.isArray(topic) && !Array.isArray(coderConfig)) { + coders[topic] = new Coder(coderConfig.fileName, coderConfig.packageName, coderConfig.messageType); + } else { + throw new Error("Please provide valid coder config or topic"); + } + } + + if (!topic || !coders) { + throw new Error("Please provide coders or topic"); + } + + let consumer: AsynchronousConsumer | SynchronousConsumer | null = null; + + if (type === "asynchronous") { + consumer = new AsynchronousConsumer(topic, coders, config); + } + + if (type === "synchronous") { + consumer = new SynchronousConsumer(topic, coders, config); + } + + if (consumer) { + consumer.start(observer); + return consumer; + } + + throw new Error("Invalid type"); +} diff --git a/public/kafka/consumer/synchronous_consumer.ts b/public/kafka/consumer/synchronous_consumer.ts new file mode 100644 index 0000000..659e82e --- /dev/null +++ b/public/kafka/consumer/synchronous_consumer.ts @@ -0,0 +1 @@ +export * from "@internal/kafka/consumer/synchronous_consumer.js"; diff --git a/public/kafka/producer/asynchronous_producer.ts b/public/kafka/producer/asynchronous_producer.ts new file mode 100644 index 0000000..edff06b --- /dev/null +++ b/public/kafka/producer/asynchronous_producer.ts @@ -0,0 +1 @@ +export * from "@internal/kafka/producer/asynchronous_producer.js"; diff --git a/public/kafka/producer/produce.ts b/public/kafka/producer/produce.ts new file mode 100644 index 0000000..4f6bf8b --- /dev/null +++ b/public/kafka/producer/produce.ts @@ -0,0 +1,54 @@ +import { SynchronousProducer } from "@internal/kafka/producer/synchronous_producer.js"; +import { AsynchronousProducer } from "@internal/kafka/producer/asynchronous_producer.js"; +import { IProducerConfig } from "@internal/interfaces/producer_config.js"; +import { Coder } from "@internal/coder/protobuf_coder.js"; + +/** + * Function to be used as functional implementation for the producer classes for asynchronous + * and synchronous producer. this function will create coder class if protobuf coder is required. + * type and coder can be passed if coder other that protobuf coder is needed. + * + * @param {IProducerConfig} config - producer config + * + * @returns {AsynchronousProducer | SynchronousProducer} + */ +export function produce( + config: IProducerConfig +): AsynchronousProducer | SynchronousProducer { + const type = config.type; + const encoding = config.encoding; + let coder = config.coder; + const coderConfig = config.coderConfig; + delete config.type; + delete config.encoding; + delete config.coder; + delete config.coderConfig; + + if (!encoding || encoding === 'protobuf') { + if (!coderConfig) { + throw new Error("Please provide coder config"); + } + coder = new Coder(coderConfig.fileName, coderConfig.packageName, coderConfig.messageType) + } + + if (!coder) { + throw new Error("Please provide coders"); + } + + let producer: AsynchronousProducer | SynchronousProducer | null = null; + + if (type === "asynchronous") { + producer = new AsynchronousProducer(coder, config); + } + + if (type === "synchronous") { + producer = new SynchronousProducer(coder, config); + } + + if (producer) { + producer.start(); + return producer; + } + + throw new Error("Invalid type"); +} diff --git a/public/kafka/producer/synchronous_producer.ts b/public/kafka/producer/synchronous_producer.ts new file mode 100644 index 0000000..506fd27 --- /dev/null +++ b/public/kafka/producer/synchronous_producer.ts @@ -0,0 +1 @@ +export * from "@internal/kafka/producer/synchronous_producer.js"; diff --git a/public/logger/logger.ts b/public/logger/logger.ts new file mode 100644 index 0000000..d851f79 --- /dev/null +++ b/public/logger/logger.ts @@ -0,0 +1 @@ +export * from "@internal/logger/logger.js"; diff --git a/public/mongo/database.ts b/public/mongo/database.ts new file mode 100644 index 0000000..d697e4e --- /dev/null +++ b/public/mongo/database.ts @@ -0,0 +1 @@ +export * from "@internal/mongo/database.js"; diff --git a/public/rpc/json_rpc_client.ts b/public/rpc/json_rpc_client.ts new file mode 100644 index 0000000..f44d08f --- /dev/null +++ b/public/rpc/json_rpc_client.ts @@ -0,0 +1 @@ +export * from "@internal/rpc/json_rpc_client.js"; diff --git a/schemas/block.proto b/schemas/block.proto new file mode 100644 index 0000000..64d58f4 --- /dev/null +++ b/schemas/block.proto @@ -0,0 +1,27 @@ +package blockpackage; +syntax = "proto3"; + +import "transaction.proto"; + + +message Block { + required uint64 number = 1; + required string hash = 2; + required string logsBloom = 3; + required string parentHash = 4; + required string receiptsRoot = 5; + required string stateRoot = 6; + required string transactionsRoot = 7; + required uint64 timestamp = 8; + required uint64 nonce = 9; + required uint64 gasLimit = 10; + required uint64 gasUsed = 11; + string baseFeePerGas = 12; + string difficulty = 13; + string totalDifficulty = 14; + string extraData = 15; + string sha3Uncles = 16; + string miner = 17; + string size = 18; + repeated Transaction transactions = 19; +} diff --git a/schemas/bridge_assets.proto b/schemas/bridge_assets.proto new file mode 100644 index 0000000..a3f057d --- /dev/null +++ b/schemas/bridge_assets.proto @@ -0,0 +1,44 @@ +package assetspackage; +syntax = "proto3"; + +message Networks { + uint32 origin = 1; + uint32 destination = 2; +} + +message RollupMetaData { + string bridgeContractAddress = 1; + string globalExitRootManager = 2; + Networks networks = 3; +} + +message TokenInfo { + string tokenType = 1; + uint32 originTokenNetwork = 2; + string originTokenAddress = 3; + string wrappedTokenAddress = 4; +} + +message ExitRoots { + string mainnet = 1; + string rollUp = 2; +} + +message BridgeAssets { + message BridgeEvent { + RollupMetaData rollupMetaData = 1; + string transactionHash = 2; + TokenInfo tokenInfo = 3; + string receiver = 4; + string amount = 5; + string metadata = 6; + uint64 depositCount = 7; + ExitRoots exitRoots = 8; + string depositor = 9; + uint32 leafType = 10; + } + + uint64 blockNumber = 1; + uint64 timestamp = 2; + repeated BridgeEvent data = 3; +} diff --git a/schemas/burnblock.proto b/schemas/burnblock.proto new file mode 100644 index 0000000..422b769 --- /dev/null +++ b/schemas/burnblock.proto @@ -0,0 +1,20 @@ +package burnblockpackage; +syntax = "proto3"; + +message BurnBlock { + message BurnEvent { + required string tokenType = 1; + required uint64 transactionIndex = 2; + required string transactionHash = 3; + required string withdrawInitiator = 4; + required string childToken = 5; + repeated string amounts = 6; + repeated uint64 tokenIds = 7; + string bridgeType = 8; + + } + + required uint64 blockNumber = 1; + required uint64 timestamp = 2; + repeated BurnEvent data = 3; +} diff --git a/schemas/checkpointblock.proto b/schemas/checkpointblock.proto new file mode 100644 index 0000000..6493489 --- /dev/null +++ b/schemas/checkpointblock.proto @@ -0,0 +1,21 @@ +package checkpointblockpackage; +syntax = "proto3"; + +message CheckpointBlock { + message CheckpointEvent { + required string transactionHash = 1; + required string proposer = 2; + required uint64 start = 3; + required uint64 end = 4; + required uint64 checkpointNumber = 5; + required uint64 transactionIndex = 6; + required string root = 7; + required uint64 headerBlockId = 8; + required string reward = 9; + required string input = 10; + } + + required uint64 blockNumber = 1; + required uint64 timestamp = 2; + repeated CheckpointEvent data = 3; +} diff --git a/schemas/claim_assets.proto b/schemas/claim_assets.proto new file mode 100644 index 0000000..223590f --- /dev/null +++ b/schemas/claim_assets.proto @@ -0,0 +1,18 @@ +package assetspackage; +syntax = "proto3"; +import public "bridge_assets.proto"; + +message ClaimAssets { + message ClaimEvent { + RollupMetaData rollupMetaData = 1; + string transactionHash = 2; + TokenInfo tokenInfo = 3; + string receiver = 4; + string amount = 5; + uint32 index = 6; + } + + uint64 blockNumber = 1; + uint64 timestamp = 2; + repeated ClaimEvent data = 3; +} diff --git a/schemas/depositblock.proto b/schemas/depositblock.proto new file mode 100644 index 0000000..9fdcf11 --- /dev/null +++ b/schemas/depositblock.proto @@ -0,0 +1,20 @@ +package depositblockpackage; +syntax = "proto3"; + +message DepositBlock { + message DepositEvent { + required string tokenType = 1; + required string bridgeType = 2; + required string transactionHash = 3; + required string depositor = 4; + required string depositReceiver = 5; + required string rootToken = 6; + repeated string amounts = 7; + repeated uint64 tokenIds = 8; + string rootTunnelAddress = 9; + } + + required uint64 blockNumber = 1; + required uint64 timestamp = 2; + repeated DepositEvent data = 3; +} diff --git a/schemas/eventlog.proto b/schemas/eventlog.proto new file mode 100644 index 0000000..36537f3 --- /dev/null +++ b/schemas/eventlog.proto @@ -0,0 +1,14 @@ +package blockpackage; +syntax = "proto3"; + +message EventLog { + required string address = 1; + required string data = 2; + required uint64 logIndex = 3; + repeated string topics = 4; + required string transactionHash = 5; + required uint64 transactionIndex = 6; + required uint64 blockNumber = 7; + required string blockHash = 8; + bool removed = 9; +} diff --git a/schemas/l1_state.proto b/schemas/l1_state.proto new file mode 100644 index 0000000..4a7c42a --- /dev/null +++ b/schemas/l1_state.proto @@ -0,0 +1,20 @@ +package l1stateblockpackage; +syntax = "proto3"; + +message ExitRoots { + string mainnet = 1; + string rollUp = 2; +} + +message L1StateBlock { + message L1State { + uint64 batchNumber = 1; + string aggregator = 2; + bool isTrusted = 3; + ExitRoots exitRoots = 4; + } + + uint64 blockNumber = 1; + uint64 timestamp = 2; + repeated L1State data = 3; +} diff --git a/schemas/mappings.proto b/schemas/mappings.proto new file mode 100644 index 0000000..b3176ce --- /dev/null +++ b/schemas/mappings.proto @@ -0,0 +1,22 @@ +package assetspackage; +syntax = "proto3"; +import public "bridge_assets.proto"; + +message Mappings { + message Metadata { + string name = 1; + string symbol = 2; + uint32 decimal = 3; + } + + message MappingEvent { + string transactionHash = 1; + TokenInfo tokenInfo = 2; + uint32 wrappedTokenNetwork = 3; + Metadata metadata = 4; + } + + uint64 blockNumber = 1; + uint64 timestamp = 2; + repeated MappingEvent data = 3; +} diff --git a/schemas/new_batch.proto b/schemas/new_batch.proto new file mode 100644 index 0000000..a7ba72a --- /dev/null +++ b/schemas/new_batch.proto @@ -0,0 +1,9 @@ +package batchpackage; +syntax = "proto3"; + +message Batch { + required uint64 number = 1; + required string globalExitRoot = 2; + required string mainnetExitRoot = 3; + required string rollupExitRoot = 4; +} diff --git a/schemas/posmapping.proto b/schemas/posmapping.proto new file mode 100644 index 0000000..dc4376f --- /dev/null +++ b/schemas/posmapping.proto @@ -0,0 +1,18 @@ +package posmappingpackage; +syntax = "proto3"; + +message Mappings { + message MappingEvent { + string transactionHash = 1; + string rootToken = 2; + string childToken = 3; + string tokenType = 4; + string bridgeType = 5; + string tokenTypeHash = 6; + string rootTunnel = 7; + } + + uint64 blockNumber = 1; + uint64 timestamp = 2; + repeated MappingEvent data = 3; +} diff --git a/schemas/statesync.proto b/schemas/statesync.proto new file mode 100644 index 0000000..d6eb8cc --- /dev/null +++ b/schemas/statesync.proto @@ -0,0 +1,15 @@ +package statesyncpackage; +syntax = "proto3"; + +message StateSync { + message DepositEvent { + required uint64 stateId = 1; + string contractAddress = 2; + string data = 3; + uint64 timestamp = 4; + } + + required uint64 blockNumber = 1; + required uint64 timestamp = 2; + repeated DepositEvent data = 3; +} diff --git a/schemas/test.proto b/schemas/test.proto new file mode 100644 index 0000000..5573168 --- /dev/null +++ b/schemas/test.proto @@ -0,0 +1,9 @@ +package testpackage; +syntax = "proto3"; + + + +message Test { + required uint64 number = 1; + required string string = 2; +} diff --git a/schemas/transaction.proto b/schemas/transaction.proto new file mode 100644 index 0000000..a7a51dc --- /dev/null +++ b/schemas/transaction.proto @@ -0,0 +1,42 @@ +package blockpackage; +syntax = "proto3"; + +import public "eventlog.proto"; + +message TransactionReceipt { + required string transactionHash = 1; + required uint64 transactionIndex = 2; + string from = 3; + string to = 4; + required uint64 blockNumber = 5; + required string blockHash = 6; + string contractAddress = 7; + required uint64 gasUsed = 8; + required uint64 cumulativeGasUsed = 9; + repeated EventLog logs = 10; + required string logsBloom = 11; + string effectiveGasPrice = 12; + bool status = 13; +} + +message Transaction { + required string hash = 1; + required uint64 nonce = 2; + string blockHash = 3; + uint64 blockNumber = 4; + uint64 transactionIndex = 5; + required string from = 6; + string to = 7; + required string value = 8; + required string gasPrice = 9; + required uint64 gas = 10; + required string input = 11; + string maxFeePerGas = 12; + string maxPriorityFeePerGas = 13; + string chainId = 14; + string v = 15; + string r = 16; + string s = 17; + uint32 type = 18; + required TransactionReceipt receipt = 19; +} diff --git a/schemas/withdrawblock.proto b/schemas/withdrawblock.proto new file mode 100644 index 0000000..9dd3516 --- /dev/null +++ b/schemas/withdrawblock.proto @@ -0,0 +1,25 @@ +package withdrawblockpackage; +syntax = "proto3"; + +message WithdrawBlock { + message WithdrawEvent { + required string tokenType = 1; + required string bridgeType = 2; + required string transactionHash = 3; + required string withdrawReceiver = 4; + uint64 burnTransactionIndex = 5; + uint64 burnTransactionBlockNumber = 6; + string transactionType = 7; + repeated string amounts = 8; + repeated uint64 tokenIds = 9; + required bool isDecoded = 10; + required string rootToken = 11; + string rootTunnel = 12; + string exitId = 13; + + } + + required uint64 blockNumber = 1; + required uint64 timestamp = 2; + repeated WithdrawEvent data = 3; +} diff --git a/tests/__mocks__/coder.js b/tests/__mocks__/coder.js new file mode 100644 index 0000000..dde0e28 --- /dev/null +++ b/tests/__mocks__/coder.js @@ -0,0 +1,4 @@ +export const coder = { + serialize: jest.fn().mockReturnValue("demo"), + deserialize: jest.fn().mockReturnValue("demo") +}; diff --git a/tests/__mocks__/observer.js b/tests/__mocks__/observer.js new file mode 100644 index 0000000..795311a --- /dev/null +++ b/tests/__mocks__/observer.js @@ -0,0 +1,5 @@ +export const observer = { + next: jest.fn(), + error: jest.fn(), + closed: jest.fn() +} diff --git a/tests/block_getters/block_getter.test.ts b/tests/block_getters/block_getter.test.ts new file mode 100644 index 0000000..7fc4668 --- /dev/null +++ b/tests/block_getters/block_getter.test.ts @@ -0,0 +1,127 @@ +import { BlockGetter } from "../../dist/internal/block_getters/block_getter"; +import EthClass, { Eth, TransactionReceipt, BlockTransactionObject } from "web3-eth"; +import ethereumBlock from "../mock_data/ethereum_block.json"; +import ethereumFullBlock from "../mock_data/ethereum_full_block.json"; +import transactionReceipts from "../mock_data/ethereum_transaction_receipts.json"; +import { BlockProducerError } from "../../dist/internal/errors/block_producer_error"; +import { BlockFormatter } from "../../dist/internal/formatters/block_formatter"; + +class MockedBlockFormatter { + public formatRawReceipt = jest.fn(); + public formatRawTransactionObject = jest.fn(); + public formatRawBlock = jest.fn(); + public formatBlockWithTransactions = jest.fn(); + public formatTransactionObject = jest.fn(); + public formatTransactionReceipt = jest.fn(); +} + +jest.mock("long"); +jest.mock("web3-eth"); +jest.mock("../../dist/internal/formatters/block_formatter"); + +describe("block getter", () => { + let mockedEthObject: jest.MockedObject, + blockGetter: BlockGetter, + mockedEthClass: jest.MockedClass, + mockedBlockFormatterClass: jest.MockedClass, + mockedFormatterObject: MockedBlockFormatter; + + beforeEach(() => { + mockedEthClass = EthClass as unknown as jest.MockedClass; + mockedEthObject = { + getBlock: jest.fn().mockReturnValue(ethereumBlock), + getTransactionReceipt: jest.fn().mockReturnValue(null), + getBlockNumber: jest.fn() + } as jest.MockedObject; + mockedBlockFormatterClass = BlockFormatter as jest.MockedClass; + }); + + describe("getBlockWithTransactionReceipts", () => { + beforeEach(() => { + blockGetter = new BlockGetter(mockedEthObject, 4); + mockedFormatterObject = mockedBlockFormatterClass.mock.instances[0] as unknown as MockedBlockFormatter; + }); + + test("getBlockWithTransactionReceipts must get transaction receipts for all transactions", async () => { + mockedEthObject.getTransactionReceipt.mockResolvedValue( + transactionReceipts["0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150"] as unknown as TransactionReceipt + ); + + await blockGetter.getBlockWithTransactionReceipts(67); + expect(mockedEthObject.getBlock).toBeCalledWith(67, true); + expect(mockedEthObject.getTransactionReceipt).toBeCalledTimes(5); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(1, "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150"); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(2, "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1"); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(3, "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004"); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(4, "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2"); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(5, "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9"); + }); + + test("getBlockWithTransactionReceipts must return formatted block", async () => { + mockedEthObject.getTransactionReceipt.mockResolvedValue( + transactionReceipts["0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150"] as unknown as TransactionReceipt + ); + mockedFormatterObject.formatBlockWithTransactions.mockReturnValueOnce(ethereumFullBlock); + + await expect( + blockGetter.getBlockWithTransactionReceipts(67) + ).resolves.toEqual(ethereumFullBlock); + expect(mockedFormatterObject.formatBlockWithTransactions).toBeCalledWith( + ethereumBlock, + [] + ); + }); + + }); + + test("if getTransactionReceipt fails, it retries for specified number of times", async () => { + mockedEthObject.getTransactionReceipt.mockRejectedValueOnce(new Error()) + .mockRejectedValueOnce(new Error()) + .mockResolvedValue( + transactionReceipts["0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150"] as unknown as TransactionReceipt + ); + + blockGetter = new BlockGetter(mockedEthObject, 2); + + await blockGetter.getBlockWithTransactionReceipts(67); + + expect(mockedEthObject.getBlock).toBeCalledWith(67, true); + expect(mockedEthObject.getTransactionReceipt).toBeCalledTimes(7); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(1, "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150"); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(2, "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150"); + expect(mockedEthObject.getTransactionReceipt).toHaveBeenNthCalledWith(3, "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150"); + + }); + + test("throws an error if getTransactionReceipt always returns null", async () => { + blockGetter = new BlockGetter(mockedEthObject, 2); + + await expect(async () => { + await blockGetter.getBlockWithTransactionReceipts(67); + }).rejects.toThrow(new BlockProducerError( + "Block producer error", + BlockProducerError.codes.RECEIPT_NOT_FOUND, + false, + `Transaction receipt not found for ${ethereumBlock.transactions[0].hash}.`, + "remote" + )); + }); + + test("get latest block number", async () => { + blockGetter = new BlockGetter(mockedEthObject, 2); + mockedEthObject.getBlockNumber.mockResolvedValueOnce(1); + + await expect(blockGetter.getLatestBlockNumber()).resolves.toEqual(1); + expect(mockedEthObject.getBlockNumber).toBeCalledWith(); + }); + + test("get block", async () => { + blockGetter = new BlockGetter(mockedEthObject, 2); + mockedEthObject.getBlock.mockResolvedValueOnce( + ethereumBlock as unknown as BlockTransactionObject + ); + + await expect(blockGetter.getBlock(1)).resolves.toEqual(ethereumBlock); + expect(mockedEthObject.getBlock).toBeCalledWith(1); + }); +}); diff --git a/tests/block_getters/block_getter_worker.test.ts b/tests/block_getters/block_getter_worker.test.ts new file mode 100644 index 0000000..269176a --- /dev/null +++ b/tests/block_getters/block_getter_worker.test.ts @@ -0,0 +1,151 @@ +import { BlockGetter } from "../../dist/internal/block_getters/block_getter"; +import fullEthereumBlock from "../mock_data/ethereum_full_block.json"; +import { IBlock } from "../../dist/internal/interfaces/block"; +import { parentPort } from "worker_threads"; +import EthClass, { Eth } from "web3-eth"; + +jest.mock("../../dist/internal/block_getters/block_getter"); +jest.mock("web3-eth"); +jest.mock("worker_threads", () => { + return { + parentPort: { + on: jest.fn(), + postMessage: jest.fn() + }, + workerData: { + endpoint: "mock_endpoint", + maxRetries: 5 + }, + + threadId: 1 + } +}); + +describe("Block getter worker", () => { + let mockedBlockGetterClass: jest.MockedClass, + mockedParentPort: jest.Mocked, + mockedEthClass: jest.MockedClass, + mockedEthObject: jest.MockedObject; + + let mockedBlockGetterObject: jest.MockedObject = { + getBlockWithTransactionReceipts: jest.fn() + } as jest.MockedObject; + + describe("with worker data and parent port", () => { + beforeEach(async () => { + jest.resetModules(); + + mockedBlockGetterClass = ( + await import("../../dist/internal/block_getters/block_getter") + ).BlockGetter as jest.MockedClass; + mockedParentPort = ( + await import("worker_threads") + ).parentPort as jest.Mocked; + mockedEthClass = EthClass as unknown as jest.MockedClass; + mockedEthObject = { + getBlock: jest.fn(), + getTransactionReceipt: jest.fn(), + getBlockNumber: jest.fn() + } as jest.MockedObject; + + + //@ts-ignore + mockedEthClass.mockReturnValue(mockedEthObject); + mockedBlockGetterClass.mockReturnValue(mockedBlockGetterObject); + + //@ts-ignore + await import("../../dist/internal/block_getters/block_getter_worker"); + }); + + test("creates block getter class on import", () => { + expect(mockedBlockGetterClass).toBeCalledWith({}, 5) + }); + + test("calls parentPort.on to register call handler", () => { + expect(mockedParentPort?.on).toBeCalledWith("message", expect.anything()); + }); + + test("on message, calls getBlockWithTransactionReceipts on block getter", () => { + mockedParentPort?.on.mock.calls[0][1]({ + blockNumber: 123, + callBackId: 1234 + }); + + expect(mockedBlockGetterObject.getBlockWithTransactionReceipts).toBeCalledWith(123) + }); + + test("on error, sends error object to parent", async () => { + mockedBlockGetterObject.getBlockWithTransactionReceipts.mockRejectedValueOnce( + new Error("mock") + ) + await mockedParentPort?.on.mock.calls[0][1]({ + blockNumber: 123, + callBackId: 1234 + }); + + expect(mockedParentPort?.postMessage).toBeCalledWith({ + callBackId: 1234, + error: new Error("mock") + }) + }); + + test("Sends full block to parent on success", async () => { + mockedBlockGetterObject.getBlockWithTransactionReceipts.mockResolvedValueOnce(fullEthereumBlock as unknown as IBlock); + await mockedParentPort?.on.mock.calls[0][1]({ + blockNumber: 123, + callBackId: 1234 + }); + + expect(mockedParentPort?.postMessage).toBeCalledWith({ + block: fullEthereumBlock, + error: null, + callBackId: 1234 + }) + }); + }); + + describe("process.exit handling", () => { + let mockedExit: jest.SpiedFunction; + + beforeEach(async () => { + jest.resetModules(); + jest.doMock("worker_threads", () => { + return { + parentPort: undefined, + workerData: { + endpoint: "mock_endpoint", + maxRetries: 5 + }, + + threadId: null + } + }); + + mockedBlockGetterClass = ( + await import("../../dist/internal/block_getters/block_getter") + ).BlockGetter as jest.MockedClass; + + mockedParentPort = ( + await import("worker_threads") + ).parentPort as jest.Mocked; + + mockedExit = jest.spyOn(process, 'exit').mockImplementation( + //@ts-ignore + (code) => { } // Need to add tsignore as return type is 'never' + ); + + //@ts-ignore + mockedBlockGetterClass.mockReturnValue(mockedBlockGetterObject); + + //Try catch added to ignore the uncaught error of process not ending as it is mocked. + try { + //@ts-ignore + await import("../../dist/internal/block_getters/block_getter_worker"); + } catch { } + }); + + test("must call process.exits", () => { + expect(mockedExit).toBeCalledWith(1); + }); + }); +}); diff --git a/tests/block_getters/erigon_block_getter.test.ts b/tests/block_getters/erigon_block_getter.test.ts new file mode 100644 index 0000000..14a1ad1 --- /dev/null +++ b/tests/block_getters/erigon_block_getter.test.ts @@ -0,0 +1,223 @@ +import { ErigonBlockGetter } from "../../dist/internal/block_getters/erigon_block_getter"; +import { BlockGetter } from "../../dist/internal/block_getters/block_getter"; +import EthClass, { Eth, BlockTransactionObject } from "web3-eth"; +import ethereumBlock from "../mock_data/ethereum_block.json"; +import ethereumFullBlock from "../mock_data/ethereum_full_block.json"; +import transactionReceipts from "../mock_data/ethereum_transaction_receipts_array.json"; +import { WebsocketProvider } from "web3-core"; +import { IBlock } from "../../dist/internal/interfaces/block"; +import utils from "web3-utils"; + +const mockedFormatterObject = { + formatRawReceipt: jest.fn(), + formatTransactionObject: jest.fn(), + formatBlockWithTransactions: jest.fn() +} + +//Manual mock required for protected eth object. +jest.mock("../../dist/internal/block_getters/block_getter", () => { + return { + BlockGetter: jest.fn().mockImplementation(function (ethObject, maxRetries) { + //@ts-ignore + this.eth = ethObject; + + //@ts-ignore + this.maxRetries = maxRetries; + + //@ts-ignore + this.getTransactionReceipt = jest.fn(); + + //@ts-ignore + this.formatTransactionObject = mockedFormatterObject.formatTransactionObject; + + //@ts-ignore + this.formatBlockWithTransactions = mockedFormatterObject.formatBlockWithTransactions; + + //@ts-ignore + this.formatRawReceipt = mockedFormatterObject.formatRawReceipt; + + //@ts-ignore + return this; + }) + } +}); +jest.mock("web3-core-helpers"); +jest.mock("web3-eth"); +jest.mock("long"); +jest.mock("web3-utils"); + +describe("Erigon node block getter", () => { + let erigonBlockGetter: ErigonBlockGetter, + mockedEthClass: jest.MockedClass, + mockedBlockGetterClass: jest.MockedClass, + mockedEthObject: jest.MockedObject, + mockedBlockGetter: jest.MockedObject, + mockedWeb3Utils: jest.MockedObject, + mockedBlockFormatterObject: jest.MockedObject; + + beforeEach(() => { + mockedEthClass = EthClass as unknown as jest.MockedClass; + mockedEthObject = { + getBlock: jest.fn().mockReturnValue(ethereumBlock), + getTransactionReceipt: jest.fn().mockReturnValue(null), + getBlockNumber: jest.fn(), + currentProvider: { + send: jest.fn() + } + } as unknown as jest.MockedObject; + }); + + describe("getBlockWithTransactionReceipts", () => { + beforeEach(() => { + mockedBlockGetterClass = BlockGetter as jest.MockedClass; + erigonBlockGetter = new ErigonBlockGetter(mockedEthObject); + + mockedWeb3Utils = utils as jest.MockedObject; + mockedBlockGetter = mockedBlockGetterClass.mock.instances[0] as jest.MockedObject; + mockedBlockFormatterObject = mockedFormatterObject; + }); + + test("getBlockWithTransactionReceipts must convert the received response", async () => { + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + mockedEthObject.getBlock.mockResolvedValueOnce(ethereumBlock as unknown as BlockTransactionObject); + + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementationOnce((event, handler) => { + handler( + null, + { + result: transactionReceipts, + jsonrpc: "2.0", + id: "mock_id" + }); + + }); + + await erigonBlockGetter.getBlockWithTransactionReceipts(67); + + expect(mockedWeb3Utils.numberToHex).toBeCalledWith(67); + expect(mockedBlockFormatterObject.formatBlockWithTransactions).toBeCalledWith(ethereumBlock, []); + expect(mockedBlockFormatterObject.formatTransactionObject).toBeCalledTimes(ethereumBlock.transactions.length); + expect(mockedBlockFormatterObject.formatRawReceipt).toBeCalledTimes(ethereumBlock.transactions.length); + + expect( + (mockedEthObject.currentProvider as jest.Mocked).send + ).toBeCalledWith( + { + id: expect.anything(), + method: "eth_getBlockReceipts", + params: ["0x0"], + jsonrpc: "2.0" + }, + expect.anything() + ); + }); + + test("getBlockWithTransactionReceipts must return the right values", async () => { + //@ts-ignore + mockedBlockFormatterObject.formatBlockWithTransactions.mockReturnValueOnce(ethereumFullBlock); + + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + mockedEthObject.getBlock.mockResolvedValueOnce(ethereumBlock as unknown as BlockTransactionObject); + + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementationOnce((event, handler) => { + handler( + null, + { + result: transactionReceipts, + jsonrpc: "2.0", + id: "mock_id" + }); + + }); + + await expect(erigonBlockGetter.getBlockWithTransactionReceipts(67)).resolves.toEqual( + ethereumFullBlock + ); + }); + + test("getBlockWithTransactionReceipts must try twice to get transaction receipts if first request returns null", async () => { + //@ts-ignore + mockedBlockFormatterObject.formatBlockWithTransactions.mockReturnValueOnce(ethereumFullBlock); + + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + mockedEthObject.getBlock.mockResolvedValueOnce(ethereumBlock as unknown as BlockTransactionObject); + + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementationOnce((event, handler) => { + handler( + null, + { + result: null, + jsonrpc: "2.0", + id: "mock_id" + }); + + }); + + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementationOnce((event, handler) => { + handler( + null, + { + result: transactionReceipts, + jsonrpc: "2.0", + id: "mock_id" + }); + + }); + + await expect(erigonBlockGetter.getBlockWithTransactionReceipts(67)).resolves.toEqual( + ethereumFullBlock + ); + expect((mockedEthObject.currentProvider as jest.Mocked).send).toBeCalledTimes(2); + }); + + test("getBlockWithTransactionReceipts must reject with error if response takes more than 45 seconds", async () => { + jest.useFakeTimers(); + + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + + try { + const promise: Promise = erigonBlockGetter.getBlockWithTransactionReceipts(67); + + jest.runAllTimers(); + + await promise; + } catch (error) { + expect(error).toEqual( + new Error(`Request timed out for block: 67`) + ); + }; + }); + }); + + describe("getBlockWithTransactionReceipts - retries", () => { + beforeEach(() => { + mockedBlockGetterClass = BlockGetter as jest.MockedClass; + erigonBlockGetter = new ErigonBlockGetter(mockedEthObject, 5); + + //@ts-ignore + mockedWeb3Utils = utils; + mockedBlockGetter = mockedBlockGetterClass.mock.instances[0] as jest.MockedObject; + }); + + test("getBlockWithTransactionReceipts must retry upto max retry times on error", async () => { + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementation((event, handler) => { + handler( + new Error("mock_error"), + { + result: null, + jsonrpc: "2.0", + id: "mock_id" + } + ); + }); + + await expect(erigonBlockGetter.getBlockWithTransactionReceipts(67)).rejects.toEqual( + new Error("mock_error") + ); + expect( + (mockedEthObject.currentProvider as jest.Mocked).send + ).toBeCalledTimes(6); + }); + }); +}); diff --git a/tests/block_getters/quicknode_block_getter.test.ts b/tests/block_getters/quicknode_block_getter.test.ts new file mode 100644 index 0000000..d4bbb70 --- /dev/null +++ b/tests/block_getters/quicknode_block_getter.test.ts @@ -0,0 +1,194 @@ +import { QuickNodeBlockGetter } from "../../dist/internal/block_getters/quicknode_block_getter"; +import { BlockGetter } from "../../dist/internal/block_getters/block_getter"; +import EthClass, { Eth } from "web3-eth"; +import ethereumBlock from "../mock_data/ethereum_block.json"; +import ethereumFullBlock from "../mock_data/ethereum_full_block.json"; +import transactionReceipts from "../mock_data/ethereum_transaction_receipts_array.json"; +import { WebsocketProvider } from "web3-core"; +import { IBlock } from "../../dist/internal/interfaces/block"; +import rawBlock from "../mock_data/raw_ethereum_block.json"; +import utils from "web3-utils"; + +const mockedFormatterObject = { + formatRawReceipt: jest.fn(), + formatRawTransactionObject: jest.fn(), + formatRawBlock: jest.fn() +} + +//Manual mock required for protected eth object. +jest.mock("../../dist/internal/block_getters/block_getter", () => { + return { + BlockGetter: jest.fn().mockImplementation(function (ethObject, maxRetries) { + //@ts-ignore + this.eth = ethObject; + + //@ts-ignore + this.maxRetries = maxRetries; + + //@ts-ignore + this.formatTransactionObject = jest.fn(); + + //@ts-ignore + this.getTransactionReceipt = jest.fn(); + + //@ts-ignore + this.formatRawBlock = mockedFormatterObject.formatRawBlock; + + //@ts-ignore + this.formatRawTransactionObject = mockedFormatterObject.formatRawTransactionObject; + + //@ts-ignore + this.formatRawReceipt = mockedFormatterObject.formatRawReceipt; + + //@ts-ignore + return this; + }) + } +}); +jest.mock("web3-core-helpers"); +jest.mock("web3-eth"); +jest.mock("long"); +jest.mock("web3-utils"); + +describe("Quick node block getter", () => { + jest.useFakeTimers(); + + let qnBlockGetter: QuickNodeBlockGetter, + mockedEthClass: jest.MockedClass, + mockedBlockGetterClass: jest.MockedClass, + mockedEthObject: jest.MockedObject, + mockedBlockGetter: jest.MockedObject, + mockedWeb3Utils: jest.MockedObject, + mockedBlockFormatterObject: jest.MockedObject; + + beforeEach(() => { + mockedEthClass = EthClass as unknown as jest.MockedClass; + mockedEthObject = { + getBlock: jest.fn().mockReturnValue(ethereumBlock), + getTransactionReceipt: jest.fn().mockReturnValue(null), + getBlockNumber: jest.fn(), + currentProvider: { + send: jest.fn() + } + } as unknown as jest.MockedObject; + }); + + describe("getBlockWithTransactionReceipts", () => { + beforeEach(() => { + mockedBlockGetterClass = BlockGetter as jest.MockedClass; + qnBlockGetter = new QuickNodeBlockGetter(mockedEthObject); + + mockedWeb3Utils = utils as jest.MockedObject; + mockedBlockGetter = mockedBlockGetterClass.mock.instances[0] as jest.MockedObject; + mockedBlockFormatterObject = mockedFormatterObject; + }); + + test("getBlockWithTransactionReceipts must convert the received response", async () => { + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementationOnce((event, handler) => { + handler( + null, + { + result: { + block: rawBlock, + receipts: transactionReceipts + }, + jsonrpc: "2.0", + id: "mock_id" + }); + + }); + + await qnBlockGetter.getBlockWithTransactionReceipts(67); + + expect(mockedWeb3Utils.numberToHex).toBeCalledWith(67); + expect(mockedBlockFormatterObject.formatRawBlock).toBeCalledWith(rawBlock, []); + //@ts-ignore + expect(mockedBlockFormatterObject.formatRawTransactionObject).toBeCalledTimes(rawBlock.transactions.length); + expect(mockedBlockFormatterObject.formatRawReceipt).toBeCalledTimes(rawBlock.transactions.length); + + expect( + (mockedEthObject.currentProvider as jest.Mocked).send + ).toBeCalledWith( + { + id: expect.anything(), + method: "qn_getBlockWithReceipts", + params: ["0x0"], + jsonrpc: "2.0" + }, + expect.anything() + ); + }); + + test("getBlockWithTransactionReceipts must return the right values", async () => { + //@ts-ignore + mockedBlockFormatterObject.formatRawBlock.mockReturnValueOnce(ethereumFullBlock); + + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementationOnce((event, handler) => { + handler(null, + { + result: { + block: ethereumBlock, + receipts: transactionReceipts + }, + jsonrpc: "2.0", + id: "mock_id" + }); + + }); + + await expect(qnBlockGetter.getBlockWithTransactionReceipts(67)).resolves.toEqual( + ethereumFullBlock + ); + }); + + test("getBlockWithTransactionReceipts must reject with error if response takes more than 45 seconds", async () => { + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + + try { + const promise: Promise = qnBlockGetter.getBlockWithTransactionReceipts(67); + + jest.runAllTimers(); + + await promise; + } catch (error) { + expect(error).toEqual( + new Error(`Request timed out for block: 67`) + ); + }; + }); + }); + + describe("getBlockWithTransactionReceipts - retries", () => { + beforeEach(() => { + mockedBlockGetterClass = BlockGetter as jest.MockedClass; + qnBlockGetter = new QuickNodeBlockGetter(mockedEthObject, 5); + + //@ts-ignore + mockedWeb3Utils = utils; + mockedBlockGetter = mockedBlockGetterClass.mock.instances[0] as jest.MockedObject; + }); + + test("getBlockWithTransactionReceipts must retry upto max retry times on error", async () => { + mockedWeb3Utils.numberToHex.mockReturnValueOnce("0x0"); + (mockedEthObject.currentProvider as jest.Mocked).send.mockImplementation((event, handler) => { + handler( + new Error("mock_error"), + { + result: null, + jsonrpc: "2.0", + id: "mock_id" + } + ); + }); + + await expect(qnBlockGetter.getBlockWithTransactionReceipts(67)).rejects.toEqual( + new Error("mock_error") + ); + expect( + (mockedEthObject.currentProvider as jest.Mocked).send + ).toBeCalledTimes(6); + }); + }); +}); diff --git a/tests/block_producer/block_producer.test.ts b/tests/block_producer/block_producer.test.ts new file mode 100644 index 0000000..24959a4 --- /dev/null +++ b/tests/block_producer/block_producer.test.ts @@ -0,0 +1,586 @@ +import { IProducedBlock, IProducedBlocksModel } from "../../dist/internal/block_producers/produced_blocks_model"; +import { AsynchronousProducer } from "../../dist/internal/kafka/producer/asynchronous_producer"; +import { ProducedBlocksModel } from "../../dist/internal/block_producers/produced_blocks_model"; +import { IBlockProducerConfig } from "../../dist/internal/interfaces/block_producer_config"; +import { BlockSubscription } from "../../dist/internal/block_subscription/block_subscription"; +import { BlockProducerError } from "../../dist/internal/errors/block_producer_error"; +import { BlockProducer } from "../../dist/internal/block_producers/block_producer"; +import fullEthereumBlock from "../mock_data/ethereum_full_block.json"; +import ethereumBlock from "../mock_data/ethereum_block.json"; +import { Logger } from "../../dist/internal/logger/logger"; +import { Coder } from "../../dist/internal/coder/protobuf_coder"; +import { Database } from "../../dist/internal/mongo/database"; +import { Metadata, DeliveryReport } from "node-rdkafka"; +import { Queue } from "../../dist/internal/queue/queue"; +import EthClass, { Eth, Block } from "web3-eth"; +import { IBlockSubscription } from "../../dist/internal/interfaces/block_subscription"; +import { IBlock } from "../../dist/internal/interfaces/block"; +import { BlockGetter } from "../../dist/internal/block_getters/block_getter"; +//@ts-ignore +import LongImport, * as Long from "long"; + +jest.mock("../../dist/internal/kafka/producer/asynchronous_producer"); +jest.mock("../../dist/internal/block_producers/produced_blocks_model"); +jest.mock("../../dist/internal/block_subscription/block_subscription"); +jest.mock("../../dist/internal/logger/logger"); +jest.mock("../../dist/internal/coder/protobuf_coder"); +jest.mock("../../dist/internal/mongo/database"); +jest.mock("../../dist/internal/queue/queue"); +jest.mock("web3-eth"); +jest.mock("long"); +jest.mock("../../dist/internal/block_getters/block_getter"); + +describe("Block Producer", () => { + let mockedBlockSubscriptionClass: jest.MockedClass, + mockedAsynchronousProducerClass: jest.MockedClass, + mockedDatabaseClass: jest.MockedClass, + mockedProducedBlockModel: jest.Mocked>, + mockedDatabaseObject: jest.MockedObject, + mockedCoderClass: jest.MockedClass, + mockedLogger: jest.MockedClass; + + beforeEach(() => { + mockedAsynchronousProducerClass = AsynchronousProducer as jest.MockedClass; + mockedBlockSubscriptionClass = BlockSubscription as jest.MockedClass; + mockedCoderClass = Coder as jest.MockedClass; + mockedDatabaseClass = Database as jest.MockedClass; + mockedProducedBlockModel = { + get: jest.fn(), + add: jest.fn() + } as unknown as jest.Mocked>; + mockedLogger = Logger as jest.MockedClass; + }); + + describe("Instance", () => { + let mockedBlockSubscriptionObject: jest.MockedObject>, + mockedAsynchronousProducerObject: jest.MockedObject, + mockedQueueClass: jest.MockedClass, + mockedQueueObject: jest.MockedObject>, + mockedBlockGetter: jest.MockedObject, + mockedLongClass: jest.MockedClass, + mockedCoderObject: jest.MockedObject, + blockProducer: BlockProducer; + + beforeEach(() => { + mockedQueueClass = Queue as jest.MockedClass; + mockedLongClass = LongImport; + + mockedBlockSubscriptionObject = new BlockSubscription( + {} as Eth + ) as unknown as jest.MockedObject>; + mockedDatabaseObject = new Database("test.url") as jest.MockedObject; + mockedCoderObject = new Coder("test", "testpackage", "TestMessage") as jest.MockedObject; + mockedBlockGetter = { + maxRetries: 4, + getBlock: jest.fn() + } as unknown as jest.MockedObject; + + blockProducer = new BlockProducer( + mockedCoderObject, + { topic: "test" }, + mockedBlockSubscriptionObject, + mockedBlockGetter, + mockedDatabaseObject, + mockedProducedBlockModel + ); + + mockedAsynchronousProducerObject = mockedAsynchronousProducerClass.mock.instances[0] as jest.MockedObject; + mockedQueueObject = mockedQueueClass.mock.instances[0] as jest.MockedObject>; + + mockedProducedBlockModel.get.mockResolvedValue({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + number: 15400000 + }); + }); + + describe("constructor", () => { + test("Must initiate parent class with coder and producer config", () => { + expect(mockedAsynchronousProducerClass).toBeCalledWith( + mockedCoderObject, + { topic: "test", "message.max.bytes": 26214400 } + ); + }); + }); + + describe("start", () => { + test("start when called must start the asynchronous producer", async () => { + await blockProducer.start(); + + expect(mockedAsynchronousProducerObject.start).toBeCalled(); + }); + + test("start when called must subscribe to block subscription with the block store in mongo.", async () => { + await blockProducer.start(); + + expect(mockedBlockSubscriptionObject.subscribe).toBeCalledWith({ + next: expect.anything(), + error: expect.anything(), + closed: expect.anything() + }, + 15400000 + ); + }); + + test("Start must query mongoDB for latest produced block before starting", async () => { + await blockProducer.start(); + + expect(mockedProducedBlockModel.get).toBeCalledTimes(1); + expect(mockedProducedBlockModel.get).toBeCalledWith(); + }); + + test("If mongo does not return a block, then subscription must be started from start block set.", async () => { + const blockProducerWithReOrg = new BlockProducer( + mockedCoderObject, + { topic: "test" }, + mockedBlockSubscriptionObject, + mockedBlockGetter, + mockedDatabaseObject, + mockedProducedBlockModel, + 0, + 3 + ); + mockedProducedBlockModel.get.mockResolvedValueOnce(null); + mockedProducedBlockModel.get.mockResolvedValueOnce(null); + await blockProducerWithReOrg.start(); + + expect(mockedBlockSubscriptionObject.subscribe) + .toBeCalledWith( + expect.anything(), + 0 + ); + }); + + test("If mongo returns previous block and re org depth is more than 0, start block must be next block if after checking chain for hash.", async () => { + const blockProducerWithReOrg = new BlockProducer( + mockedCoderObject, + { topic: "test" }, + mockedBlockSubscriptionObject, + mockedBlockGetter, + mockedDatabaseObject, + mockedProducedBlockModel, + 0, + 3 + ); + mockedBlockGetter.getBlock.mockResolvedValueOnce(ethereumBlock as unknown as Block); + mockedBlockGetter.getBlock.mockResolvedValueOnce({ number: 0 } as Block); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + number: 15400000 + }); + + await blockProducerWithReOrg.start(); + + expect(mockedBlockGetter.getBlock).toBeCalledWith(15400000); + expect(mockedBlockSubscriptionObject.subscribe) + .toBeCalledWith( + expect.anything(), + 15400001 + ); + }); + + test("If latest produced block does not match hash on chain, the block before that must be checked until equal", async () => { + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15400000 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15400000 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + number: 15399999 + }); + const blockProducerWithReOrg = new BlockProducer( + mockedCoderObject, + { topic: "test" }, + mockedBlockSubscriptionObject, + mockedBlockGetter, + mockedDatabaseObject, + mockedProducedBlockModel, + 0, + 3 + ); + + const olderEthereumBlock = Object.assign({}, ethereumBlock); + + mockedBlockGetter.getBlock.mockResolvedValueOnce(olderEthereumBlock as unknown as Block); + mockedBlockGetter.getBlock.mockResolvedValueOnce(Object.assign( + olderEthereumBlock as unknown as Block, + { number: 15399999 } + )); + mockedBlockGetter.getBlock.mockResolvedValueOnce({ number: 0 } as Block); + + await blockProducerWithReOrg.start(); + + // 3 times including eth.getBlock for latest finalized block. + expect(mockedBlockGetter.getBlock).toBeCalledTimes(2); + expect(mockedBlockGetter.getBlock).toHaveBeenNthCalledWith(1, 15400000); + expect(mockedBlockGetter.getBlock).toHaveBeenNthCalledWith(2, 15399999); + expect(mockedBlockSubscriptionObject.subscribe) + .toBeCalledWith( + expect.anything(), + 15400000 + ); + }); + + + + test("If mongo does not return a block in middle of check, then subscription must be started from that depth.", async () => { + const blockProducerWithReOrg = new BlockProducer( + mockedCoderObject, + { topic: "test" }, + mockedBlockSubscriptionObject, + mockedBlockGetter, + mockedDatabaseObject, + mockedProducedBlockModel, + 0, + 3 + ); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15400000 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15400000 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce(null); + + mockedBlockGetter.getBlock.mockResolvedValueOnce(ethereumBlock as unknown as Block); + + await blockProducerWithReOrg.start(); + + expect(mockedBlockSubscriptionObject.subscribe) + .toBeCalledWith( + expect.anything(), + 15399999 + ); + }); + + test("If latest produced blocks does not match hash on chain, the block before that must be checked until max re org depth", async () => { + const blockProducerWithReOrg = new BlockProducer( + mockedCoderObject, + { topic: "test" }, + mockedBlockSubscriptionObject, + mockedBlockGetter, + mockedDatabaseObject, + mockedProducedBlockModel, + 0, + 3 + ); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15400000 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15400000 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15399999 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15399998 + }); + mockedProducedBlockModel.get.mockResolvedValueOnce({ + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb03", + number: 15399997 + }); + + const olderEthereumBlock = Object.assign({}, ethereumBlock); + + mockedBlockGetter.getBlock.mockResolvedValueOnce(olderEthereumBlock as unknown as Block); + mockedBlockGetter.getBlock.mockResolvedValueOnce(Object.assign( + olderEthereumBlock as unknown as Block, + { number: 15399999 } + )); + mockedBlockGetter.getBlock.mockResolvedValueOnce(Object.assign( + olderEthereumBlock as unknown as Block, + { number: 15399998 } + )); + mockedBlockGetter.getBlock.mockResolvedValueOnce({ number: 0 } as Block); + + await blockProducerWithReOrg.start(); + + expect(mockedBlockGetter.getBlock).toBeCalledTimes(3); + expect(mockedBlockGetter.getBlock).toHaveBeenNthCalledWith(1, 15400000); + expect(mockedBlockGetter.getBlock).toHaveBeenNthCalledWith(2, 15399999); + expect(mockedBlockGetter.getBlock).toHaveBeenNthCalledWith(3, 15399998); + expect(mockedBlockSubscriptionObject.subscribe) + .toBeCalledWith( + expect.anything(), + 15399997 + ); + }); + + test("start on success must return producer metadata.", async () => { + mockedAsynchronousProducerObject.start.mockResolvedValueOnce( + { orig_broker_id: 12 } as Metadata + ); + + await expect(blockProducer.start()).resolves.toEqual( + { orig_broker_id: 12 } + ); + }); + + test("start on next block, the block must be produced to producer with right params", async () => { + //@ts-ignore + mockedLongClass.fromValue.mockReturnValue({ + toNumber: jest.fn().mockReturnValueOnce(123), + toString: jest.fn().mockReturnValueOnce("123") + }); + + await blockProducer.start(); + await mockedBlockSubscriptionObject.subscribe.mock.calls[0][0].next(fullEthereumBlock as unknown as IBlock); + + expect(mockedAsynchronousProducerObject.produceEvent).toHaveBeenCalledWith( + "123", + fullEthereumBlock, + undefined, + undefined, + undefined, + { + number: 123, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + } + ); + }); + + test("On fatal thrown by block subscription, it must be restarted and error logged.", async () => { + await blockProducer.start(); + await mockedBlockSubscriptionObject.subscribe.mock.calls[0][0].error( + new BlockProducerError( + "Error in block subscription", + BlockProducerError.codes.OBSERVER_NOT_SET, + true, + "Subscription not started with observer.", + "local", + ) + ); + + expect(mockedLogger.error).toBeCalledWith( + new BlockProducerError( + "Error in block subscription", + BlockProducerError.codes.OBSERVER_NOT_SET, + true, + "Subscription not started with observer.", + "local", + ) + ); + expect(mockedBlockSubscriptionObject.unsubscribe).toHaveBeenCalled(); + expect(mockedBlockSubscriptionObject.subscribe).toHaveBeenCalled(); + }); + + test("On error thrown by restart block subscription, no error must be thrown by producer but logged", async () => { + mockedBlockSubscriptionObject.unsubscribe.mockRejectedValueOnce(new Error("demo")); + await blockProducer.start(); + + await expect( + mockedBlockSubscriptionObject.subscribe.mock.calls[0][0].error( + new BlockProducerError( + "Error in block subscription", + BlockProducerError.codes.OBSERVER_NOT_SET, + true, + "Subscription not started with observer.", + "local", + ) + )).resolves.toBe(undefined); + expect(mockedLogger.error).toBeCalledWith( + new BlockProducerError( + "Error in block subscription", + BlockProducerError.codes.OBSERVER_NOT_SET, + true, + "Subscription not started with observer.", + "local", + ) + ); + }); + + test("On fatal thrown by produceEvent, block producer and block subscription must be restarted and incident logged.", async () => { + mockedAsynchronousProducerObject.produceEvent.mockRejectedValueOnce({ isFatal: true, code: 3001 }); + await blockProducer.start(); + await mockedBlockSubscriptionObject.subscribe.mock.calls[0][0].next( + fullEthereumBlock as unknown as IBlock + ); + await new Promise((resolve) => { + setTimeout(() => resolve(true), 300); + }); + + expect(mockedAsynchronousProducerObject.stop).toHaveBeenCalled(); + expect(mockedAsynchronousProducerObject.start).toHaveBeenCalled(); + expect(mockedLogger.error).toBeCalledWith( + { isFatal: true, code: 3001 } + ); + expect(mockedBlockSubscriptionObject.unsubscribe).toHaveBeenCalled(); + expect(mockedBlockSubscriptionObject.subscribe).toHaveBeenCalled(); + }); + + test("On erroneous state error, fatal error event must be emitted.", async () => { + mockedAsynchronousProducerObject.produceEvent.mockRejectedValueOnce({ + message: "Local: Erroneous state", + isFatal: true, + code: 3001 + }); + + await blockProducer.start(); + await mockedBlockSubscriptionObject.subscribe.mock.calls[0][0].next( + fullEthereumBlock as unknown as IBlock + ); + await new Promise((resolve) => { + setTimeout(() => resolve(true), 300); + }); + + expect(mockedAsynchronousProducerObject.stop).toHaveBeenCalled(); + expect(mockedLogger.error).toBeCalledWith({ + message: "Local: Erroneous state", + isFatal: true, + code: 3001 + }); + expect(mockedBlockSubscriptionObject.unsubscribe).toHaveBeenCalled(); + expect(mockedAsynchronousProducerObject.emit).toBeCalledWith( + "blockProducer.fatalError", + { + message: "Local: Erroneous state", + isFatal: true, + code: 3001 + } + ); + }); + + test("On delivery report, the produced block must be added to mongoDB collection in correct order", (done) => { + expect.assertions(3); + mockedAsynchronousProducerObject.produceEvent.mockRejectedValueOnce({ isFatal: true }); + //Mock implementation to change order. + mockedProducedBlockModel.add.mockImplementationOnce(async () => { + await new Promise(resolve => setTimeout(() => { + expect(mockedProducedBlockModel.add).toHaveBeenCalledTimes(1); + resolve(true); + }, 100)); + return; + }); + + mockedQueueObject.front.mockReturnValueOnce({ + number: 15400000, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + }); + mockedQueueObject.front.mockReturnValueOnce({ + number: 15400001, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + }); + mockedQueueObject.isEmpty.mockReturnValueOnce(false); + mockedQueueObject.isEmpty.mockReturnValueOnce(false); + mockedQueueObject.isEmpty.mockReturnValueOnce(true); + + blockProducer.start().then(() => { + //@ts-ignore + mockedAsynchronousProducerObject.on.mock.calls[0][1]( + { + opaque: { + number: 15400000, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + } + } as DeliveryReport + ); + //@ts-ignore + mockedAsynchronousProducerObject.on.mock.calls[0][1]( + { + opaque: { + number: 15400001, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + } + } as DeliveryReport + ); + + setTimeout(() => { + try { + expect(mockedProducedBlockModel.add).toHaveBeenNthCalledWith( + 1, + { + number: 15400000, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + }, + 0 + ); + expect(mockedProducedBlockModel.add).toHaveBeenNthCalledWith( + 2, + { + number: 15400001, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + }, + 0 + ); + done(); + } catch (error) { + //Catch to log the test failure. + //https://jestjs.io/docs/asynchronous#:~:text=If%20done()%20is%20never,the%20catch%20block%20to%20done%20. + done(error); + } + }, 300) + }); + }); + + test("On error when adding produced block to mongoDB, no error must be thrown, must be retried upto 5 times and logged", async () => { + mockedProducedBlockModel.add.mockRejectedValueOnce( + new Error("Demo") + ); + mockedProducedBlockModel.add.mockRejectedValueOnce( + new Error("Demo") + ); + mockedProducedBlockModel.add.mockRejectedValueOnce( + new Error("Demo") + ); + mockedProducedBlockModel.add.mockRejectedValueOnce( + new Error("Demo") + ); + mockedProducedBlockModel.add.mockRejectedValueOnce( + new Error("Demo") + ); + await blockProducer.start(); + + //@ts-ignore + mockedAsynchronousProducerObject.on.mock.calls[0][1]( + { + opaque: { + number: 15400000, + hash: "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07" + } + } as DeliveryReport + ) + + await new Promise(resolve => setTimeout(() => { + resolve(true); + }, 100)); + + expect(mockedProducedBlockModel.add).toBeCalledTimes(5); + expect(mockedLogger.error).toBeCalledTimes(1); + expect(mockedLogger.error).toBeCalledWith( + BlockProducerError.createUnknown(new Error("Demo")) + ); + }); + }); + + describe("stop", () => { + test("Stop must call unsubscribe and stop", async () => { + await blockProducer.stop(); + + expect(mockedAsynchronousProducerObject.stop).toHaveBeenCalled(); + expect(mockedBlockSubscriptionObject.unsubscribe).toHaveBeenCalled(); + }); + + test("Stop must resolve to true on success", async () => { + await expect(blockProducer.stop()).resolves.toBe(true); + }); + + test("Throws error Block producer or Kafka error on exception.", async () => { + mockedAsynchronousProducerObject.stop.mockRejectedValueOnce(new Error("mock")); + + await expect(blockProducer.stop()).rejects.toEqual(BlockProducerError.createUnknown( + new Error("mock") + )); + }); + }); + }); +}); diff --git a/tests/block_producer/quicknode_block_producer.test.ts b/tests/block_producer/quicknode_block_producer.test.ts new file mode 100644 index 0000000..44c5151 --- /dev/null +++ b/tests/block_producer/quicknode_block_producer.test.ts @@ -0,0 +1,156 @@ +import { QuickNodeBlockProducer } from "../../dist/public/block_producers/quicknode_block_producer"; +import { AsynchronousProducer } from "../../dist/internal/kafka/producer/asynchronous_producer"; +import { ProducedBlocksModel } from "../../dist/internal/block_producers/produced_blocks_model"; +import { QuickNodeBlockGetter } from "../../dist/internal/block_getters/quicknode_block_getter"; +import { BlockSubscription } from "../../dist/internal/block_subscription/block_subscription"; +import { IBlockProducerConfig } from "../../dist/internal/interfaces/block_producer_config"; +import { Coder } from "../../dist/internal/coder/protobuf_coder"; +import { Database } from "../../dist/internal/mongo/database"; +import { Logger } from "../../dist/internal/logger/logger"; +import EthClass, { Eth } from "web3-eth"; + +jest.mock("../../dist/internal/kafka/producer/asynchronous_producer"); +jest.mock("../../dist/internal/block_producers/produced_blocks_model"); +jest.mock("../../dist/internal/block_subscription/block_subscription"); +jest.mock("../../dist/internal/block_getters/quicknode_block_getter"); +jest.mock("../../dist/internal/logger/logger"); +jest.mock("../../dist/internal/coder/protobuf_coder"); +jest.mock("../../dist/internal/mongo/database"); +jest.mock("web3-eth"); + +describe("Block Producer", () => { + let mockedBlockSubscriptionClass: jest.MockedClass, + mockedAsynchronousProducerClass: jest.MockedClass, + mockedDatabaseClass: jest.MockedClass, + mockedDatabaseObject: jest.MockedObject, + mockedCoderClass: jest.MockedClass, + mockedLogger: jest.MockedClass, + mockBlockProducerConfig: IBlockProducerConfig, + mockedEthClass: jest.MockedClass, + mockedProducedBlockSchema: jest.MockedObject, + mockedBlockGetter: jest.MockedClass; + + beforeEach(async () => { + mockedAsynchronousProducerClass = AsynchronousProducer as jest.MockedClass; + mockedBlockSubscriptionClass = BlockSubscription as jest.MockedClass; + mockedCoderClass = Coder as jest.MockedClass; + mockedDatabaseClass = Database as jest.MockedClass; + mockedLogger = Logger as jest.MockedClass; + mockedEthClass = EthClass as unknown as jest.MockedClass; + mockedBlockGetter = QuickNodeBlockGetter as unknown as jest.MockedClass; + + mockBlockProducerConfig = { + rpcWsEndpoints: ["rpc.com", "rpc2.com"], + startBlock: 0, + mongoUrl: "mongodb://localhost:27017/open-api", + maxReOrgDepth: 0, + topic: "demo", + blockSubscriptionTimeout: 60000 + }; + mockedProducedBlockSchema = ProducedBlocksModel as jest.MockedObject; + mockedDatabaseClass.prototype.model.mockReturnValueOnce({}); + new QuickNodeBlockProducer(mockBlockProducerConfig); + + mockedDatabaseObject = mockedDatabaseClass.mock.instances[0] as jest.MockedObject; + }); + + test("Must return an instance of BlockProducer", async () => { + expect( + new QuickNodeBlockProducer(mockBlockProducerConfig) + ).toBeInstanceOf(QuickNodeBlockProducer); + }); + + // test("When called must connect to mongoDB", async () => { + // new QuickNodeBlockProducer(mockBlockProducerConfig); + + // expect(mockedDatabaseObject.connect).toBeCalled(); + // }); + + test("Must create the database instance with passed mongouUrl", () => { + expect(mockedDatabaseClass).toBeCalledWith("mongodb://localhost:27017/open-api"); + }); + + test("Database.model must be called with ProducedBlocks as model name to get Produced blocks model.", () => { + expect(mockedDatabaseObject.model).toBeCalledWith( + "ProducedBlocks", + expect.anything(), + expect.anything() + ); + }); + + test("Database.model must be called with ProducedBlockSchema to get Produced blocks model.", () => { + expect(mockedDatabaseObject.model).toBeCalledWith( + expect.anything(), + mockedProducedBlockSchema, + expect.anything() + ); + }); + + test("Database.model must be called with chain name + producedblocks as collection name to get Produced blocks model.", () => { + expect(mockedDatabaseObject.model).toBeCalledWith( + expect.anything(), + expect.anything(), + "producedblocks" + ); + }); + + test("Web3 eth instance must be created with first endpoint passed in config.", () => { + expect(mockedEthClass.providers.WebsocketProvider).toHaveBeenCalledWith( + "rpc.com", + expect.anything() + ); + expect(mockedEthClass).toBeCalledWith( + //@ts-ignore + mockedEthClass.providers.WebsocketProvider.mock.instances[0] + ); + }); + + test("Web3 eth instance must be created with right wss connection config passed in config.", () => { + expect(mockedEthClass.providers.WebsocketProvider).toHaveBeenCalledWith( + expect.anything(), + { + reconnect: { + auto: true + }, + clientConfig: { + maxReceivedFrameSize: 1000000000, + maxReceivedMessageSize: 1000000000, + } + } + ); + + expect(mockedEthClass).toBeCalledWith( + //@ts-ignore + mockedEthClass.providers.WebsocketProvider.mock.instances[0] + ); + }); + + test("Coder instance must be created with right parameters.", () => { + expect(mockedCoderClass).toBeCalledWith( + "block", + "blockpackage", + "Block" + ); + }); + + test("BlockSubscription instance must be created with all parameters", () => { + expect(mockedBlockSubscriptionClass).toBeCalledWith( + mockedEthClass.mock.instances[0], + ["rpc.com", "rpc2.com"], + 0, + "quicknode_block_getter", + 60000 + ); + }); + + test("Non kafka config must be deleted from config object before being passed to KafkaProducer", () => { + expect(mockBlockProducerConfig).not.toEqual(expect.objectContaining({ + rpcWsEndpoints: ["rpc.com", "rpc2.com"], + startBlock: 0, + mongoUrl: "mongodb://localhost:27017/open-api", + maxReOrgDepth: 0, + maxRetries: 5, + blockSubscriptionTimeout: 60000 + })); + }); +}); diff --git a/tests/block_subscription/abstract_block_subscription.test.ts b/tests/block_subscription/abstract_block_subscription.test.ts new file mode 100644 index 0000000..477aa02 --- /dev/null +++ b/tests/block_subscription/abstract_block_subscription.test.ts @@ -0,0 +1,396 @@ +import { AbstractBlockSubscription } from "../../dist/internal/block_subscription/abstract_block_subscription"; +import { BlockProducerError } from "../../dist/internal/errors/block_producer_error"; +import fullEthereumBlock from "../mock_data/ethereum_full_block.json"; +import { IBlock } from "../../dist/internal/interfaces/block"; +import { Subscription } from "web3-core-subscriptions"; +import { Eth, BlockTransactionObject } from "web3-eth"; +//@ts-ignore +import { observer } from "../__mocks__/observer"; +import mockLog from "../mock_data/log.json"; +import { Log } from "web3-core"; +// @ts-ignore +import Long, * as LongClass from "long"; + +jest.mock("mongoose"); +jest.mock("long"); + +class BlockSubscription extends AbstractBlockSubscription { + public backFillBlocks = jest.fn() + public getBlockFromWorker = jest.fn() +} + + +describe("Abstract Block Subscription", () => { + let mockedEthObject: jest.MockedObject, + mockedLongClass: jest.MockedClass, + mockNumber: jest.MockedObject, + subscriber: BlockSubscription; + + + const on = jest.fn().mockReturnThis(); + const unsubscribe = jest.fn().mockImplementation( + (cb: (error: Error | null, success: boolean) => void) => { + cb(null, true); + } + ); + + beforeEach(() => { + mockedLongClass = Long; + mockedEthObject = { + subscribe: jest.fn().mockReturnValue({ + on, + unsubscribe + } as unknown as Subscription), + getBlock: jest.fn() + } as jest.MockedObject; + + mockNumber = { + toNumber: jest.fn().mockReturnValue(0) + }; + + subscriber = new BlockSubscription( + mockedEthObject, + 60000 + ); + + //@ts-ignore + mockedLongClass.fromValue.mockReturnValue(mockNumber); + }); + + describe("subscribe", () => { + afterEach(() => { + subscriber.unsubscribe(); + }); + + test("Must call get block to determine if backfilling is required", async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + expect( + await subscriber.subscribe(observer, 0) + ).toEqual(undefined); + + expect(mockedEthObject.getBlock).toBeCalledWith("finalized"); + }); + + test("If the difference between last block and finalized block is more than 50, log subscription must not be called but backfill", async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 51 } as BlockTransactionObject); + expect( + await subscriber.subscribe(observer, 0) + ).toEqual(undefined); + + expect(mockedEthObject.subscribe).not.toBeCalled(); + expect(subscriber.backFillBlocks).toBeCalled(); + }); + + test("must subscribe to logs when on eth class and return void if difference between finalized block and start block is less than 50", async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + expect( + await subscriber.subscribe(observer, 0) + ).toEqual(undefined); + + expect(mockedEthObject.subscribe).toBeCalled(); + }); + + test("subscribe must subscribe to data and error events of log subscription", async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + await subscriber.subscribe(observer, 0); + + expect(on).toHaveBeenNthCalledWith(1, "data", expect.anything()); + expect(on).toHaveBeenNthCalledWith(2, "error", expect.anything()); + expect(on).toHaveBeenCalledTimes(2); + }); + + test("Subscription must start from start block set if difference to finalized block is less than 50", async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + await subscriber.subscribe(observer, 0); + + expect(mockedEthObject.subscribe) + .toBeCalledWith( + "logs", + { "fromBlock": 0 } + ); + }); + + test("On new log, getBlockFromWorker must be called with block number", (done) => { + expect.assertions(1); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: fullEthereumBlock as unknown as IBlock } + ); + + subscriber.subscribe({ + next: async () => { + expect(subscriber.getBlockFromWorker).toBeCalledWith(mockLog.blockNumber); + + done(); + }, + error: observer.error, + closed: observer.closed + }, + 0 + ).then(() => { + on.mock.calls[0][1](mockLog); + }); + }); + + test("If there has been no new block for more than the timeout set, subscribe must be called again.", async () => { + expect.assertions(3); + jest.useFakeTimers(); + jest.spyOn(subscriber, "unsubscribe"); + jest.spyOn(subscriber, "subscribe"); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: fullEthereumBlock as unknown as IBlock } + ); + + await subscriber.subscribe(observer, 0); + + jest.runAllTimers(); + + jest.useRealTimers(); + + //Adding below to allow async calls to be completed before checking. + await new Promise((res) => setImmediate(res)); + + expect(subscriber.unsubscribe).toBeCalled(); + expect(subscriber.subscribe).toBeCalledTimes(2); + expect(subscriber.subscribe).toHaveBeenNthCalledWith( + 2, + observer, + 0 + ); + }); + + test("On new log, next must be called with full block data returned by worker", (done) => { + expect.assertions(1); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: fullEthereumBlock as unknown as IBlock } + ); + + subscriber.subscribe({ + next: async (block: IBlock) => { + expect(block).toEqual(fullEthereumBlock); + done(); + }, + error: observer.error, + closed: observer.closed + }, + 0 + ).then(() => { + on.mock.calls[0][1](mockLog); + }); + }); + + test("On new log, if a block is skipped, the skipped block must be enqueued.", (done) => { + expect.assertions(4); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: { ...fullEthereumBlock, number: mockNumber } as unknown as IBlock } + ); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: { ...fullEthereumBlock, number: mockNumber } as unknown as IBlock } + ); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: { ...fullEthereumBlock, number: mockNumber } as unknown as IBlock } + ); + + mockNumber.toNumber.mockReturnValueOnce(0); + mockNumber.toNumber.mockReturnValueOnce(1); + mockNumber.toNumber.mockReturnValueOnce(2); + + subscriber.subscribe(observer, + 0 + ).then(() => { + on.mock.calls[0][1]({ + ...mockLog, + blockHash: "1", + blockNumber: 0 + }); + on.mock.calls[0][1]({ + ...mockLog, + blockHash: "2", + blockNumber: 2 + }); + }); + + //Settimeout is added to the assertion behind getblock in the event loop queue. + setTimeout(() => { + expect(subscriber.getBlockFromWorker).toBeCalledTimes(3); + expect(subscriber.getBlockFromWorker).toHaveBeenNthCalledWith( + 1, + 0 + ); + expect(subscriber.getBlockFromWorker).toHaveBeenNthCalledWith( + 2, + 1 + ); + expect(subscriber.getBlockFromWorker).toHaveBeenNthCalledWith( + 3, + 2 + ); + done(); + }, 100); + }); + + test("On a re org being missed, subscription must call observer.error", (done) => { + expect.assertions(1); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: { ...fullEthereumBlock, number: mockNumber, hash: "mockHash_1" } as unknown as IBlock } + ); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: { ...fullEthereumBlock, number: mockNumber } as unknown as IBlock } + ); + + mockNumber.toNumber.mockReturnValueOnce(0); + mockNumber.toNumber.mockReturnValueOnce(1); + mockNumber.toNumber.mockReturnValueOnce(2); + + subscriber.subscribe({ + next: observer.next, + error: async (error: BlockProducerError) => { + expect(error).toEqual(BlockProducerError.createUnknown( + new Error("Chain re org not handled.") + )); + done(); + }, + closed: observer.closed + }, + 0 + ).then(() => { + on.mock.calls[0][1]({ + ...mockLog, + blockHash: "1", + blockNumber: 0 + }); + on.mock.calls[0][1]({ + ...mockLog, + blockHash: "2", + blockNumber: 1 + }); + }); + }); + + test("Subscribe must call next only once per block.", (done) => { + expect.assertions(1); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: fullEthereumBlock as unknown as IBlock } + ); + subscriber.getBlockFromWorker.mockResolvedValueOnce( + { block: fullEthereumBlock as unknown as IBlock } + ); + + subscriber.subscribe(observer, 0).then(() => { + on.mock.calls[0][1](mockLog); + on.mock.calls[0][1](mockLog); + }); + + //Settimeout is added to the assertion behind getblock in the event loop queue. + setTimeout(() => { + expect(observer.next).toBeCalledTimes(1); + done(); + }, 100); + }); + + test("On error event thrown by block getter, observer.error must be called with BlockProducerError", (done) => { + expect.assertions(2); + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + subscriber.getBlockFromWorker.mockResolvedValueOnce({ + error: new Error("demo") + }); + + subscriber.subscribe(observer, 0).then(() => { + on.mock.calls[0][1](mockLog); + }); + + setTimeout(() => { + expect(observer.error).toBeCalledTimes(1); + expect(observer.error).toBeCalledWith( + BlockProducerError.createUnknown( + new Error("demo") + ) + ); + + done(); + }, 100); + }); + + test("On error event by node subscription, observer.error must be called with BlockProducerError", (done) => { + expect.assertions(2); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + + subscriber.subscribe(observer, 0).then(() => { + on.mock.calls[1][1]( + new Error("demo") + ); + }); + + setTimeout(() => { + expect(observer.error).toBeCalledTimes(1); + expect(observer.error).toBeCalledWith( + BlockProducerError.createUnknown( + new Error("demo") + ) + ); + + done(); + }, 100); + }); + + }); + + describe("unsubscribe", () => { + test("Must resolve to true, when subscription.unsubcribe calls callback with success", + async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + + await subscriber.subscribe(observer, 0); + + await expect( + subscriber.unsubscribe() + ).resolves.toBe(true); + } + ); + + test("Must call clearTimeout", + async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + jest.spyOn(global, "clearTimeout"); + + await subscriber.subscribe(observer, 0); + await subscriber.unsubscribe(); + + expect( + clearTimeout + ).toBeCalled(); + } + ); + + test("Must throw BlockProducerError, when subscription.unsubscribe calls reports error", + async () => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 0 } as BlockTransactionObject); + unsubscribe.mockImplementationOnce( + (cb: (error: Error, success: boolean) => void) => { + cb(new Error("demo"), false); + } + ); + + await subscriber.subscribe(observer, 0); + + await expect( + subscriber.unsubscribe() + ).rejects.toEqual( + BlockProducerError.createUnknown(new Error("demo")) + ); + } + ); + }); +}); diff --git a/tests/block_subscription/block_polling.test.ts b/tests/block_subscription/block_polling.test.ts new file mode 100644 index 0000000..8136414 --- /dev/null +++ b/tests/block_subscription/block_polling.test.ts @@ -0,0 +1,112 @@ +import { BlockPoller } from "../../dist/internal/block_subscription/block_polling"; +import { BlockGetter } from "../../dist/internal/block_getters/block_getter"; +//@ts-ignore +import { blockData } from "../mock_data/zkevm_block"; +import { BlockProducerError } from "../../dist/internal/errors/block_producer_error"; +import { Eth } from "web3-eth"; + +jest.mock("web3-eth"); +jest.mock("../../dist/internal/block_getters/block_getter"); +jest.useFakeTimers(); + +let blockPoller: BlockPoller, + blockGetter: jest.Mocked; + +const observer = { + next: jest.fn().mockReturnThis(), + error: jest.fn().mockReturnThis(), + closed: jest.fn().mockReturnThis() +}; + +describe("Block Polling when latest block is more than start block", () => { + const startBlock = 59; + + beforeEach(() => { + blockGetter = new BlockGetter({} as string) as jest.Mocked; + }); + + test("test the subscribe method", async () => { + blockGetter.getBlock.mockResolvedValue(blockData); + blockGetter.getLatestBlockNumber.mockResolvedValue(60); + + blockPoller = new BlockPoller( + blockGetter, + 2000 + ); + + let counter = 0; + observer.next = jest.fn((data) => { + if (counter == 0) { + expect(blockData).toEqual(data); + expect(blockGetter.getLatestBlockNumber).toHaveBeenCalledTimes(1); + expect(blockGetter.getBlock).toHaveBeenCalledTimes(1); + expect(blockGetter.getBlock).toHaveBeenNthCalledWith(1, 59); + } + + if (counter == 1) { + expect(blockData).toEqual(data); + + expect(blockGetter.getBlock).toHaveBeenCalledTimes(2); + expect(blockGetter.getBlock).toHaveBeenNthCalledWith(2, 60); + + blockPoller.unsubscribe(); + } + + if (counter == 2) { + throw new Error("Invalid execution flow!"); + } + + counter++; + }); + + await blockPoller.subscribe(observer, startBlock); + }); + + test("test if the error is being thrown", async () => { + jest.useRealTimers(); + + blockGetter.getLatestBlockNumber.mockRejectedValue(new BlockProducerError("error while getting the latest block")); + blockPoller = new BlockPoller( + blockGetter, + 2000 + ); + + await blockPoller.subscribe(observer, 0); + await new Promise(resolve => setImmediate(resolve)); + await blockPoller.unsubscribe(); + + expect(observer.error).toHaveBeenCalledWith( + new BlockProducerError("error while getting the latest block") + ); + }); + +}); + +describe("Block Polling when latest block is less than start block", () => { + const startBlock = 61; + + beforeEach(() => { + blockGetter = new BlockGetter({} as string) as jest.Mocked; + blockGetter.getBlock.mockResolvedValueOnce(blockData); + blockGetter.getLatestBlockNumber.mockResolvedValueOnce(60); + + blockPoller = new BlockPoller( + blockGetter, + 2000 + ); + }); + + test("test the start method", async () => { + blockPoller.subscribe(observer, startBlock); + + expect(blockGetter.getLatestBlockNumber).toHaveBeenCalledTimes(1); + blockPoller.unsubscribe(); + + }); + + test("test the stop method", async () => { + blockPoller.subscribe(observer, startBlock); + blockPoller.unsubscribe(); + expect(blockGetter.getLatestBlockNumber).toHaveBeenCalledTimes(1); + }); +}); diff --git a/tests/block_subscription/block_subscription.test.ts b/tests/block_subscription/block_subscription.test.ts new file mode 100644 index 0000000..c9b30d6 --- /dev/null +++ b/tests/block_subscription/block_subscription.test.ts @@ -0,0 +1,379 @@ +import { BlockSubscription } from "../../dist/internal/block_subscription/block_subscription"; +import { BlockProducerError } from "../../dist/internal/errors/block_producer_error"; +import fullEthereumBlock from "../mock_data/ethereum_full_block.json"; +import { IBlock } from "../../dist/internal/interfaces/block"; +import { Subscription } from "web3-core-subscriptions"; +import { Eth, BlockTransactionObject } from "web3-eth"; +//@ts-ignore +import { observer } from "../__mocks__/observer"; +import { Worker } from "worker_threads"; +import { Log } from "web3-core"; + +jest.mock("worker_threads"); +jest.mock("mongoose"); +jest.mock("long"); + +class ExtendedBlockSubscription extends BlockSubscription { + public backFillBlocks() { + return super.backFillBlocks(); + } + + public getBlockFromWorker(number: number, workerId: number) { + return super.getBlockFromWorker(number, workerId); + } +} + +describe("Block Subscription", () => { + let mockedEthObject: jest.MockedObject, + mockedWorkerClass: jest.MockedClass; + + const on = jest.fn().mockReturnThis(); + const unsubscribe = jest.fn().mockImplementation( + (cb: (error: Error | null, success: boolean) => void) => { + cb(null, true); + } + ); + + beforeEach(() => { + mockedWorkerClass = Worker as jest.MockedClass; + mockedEthObject = { + subscribe: jest.fn().mockReturnValue({ + on, + unsubscribe, + } as unknown as Subscription), + getBlock: jest.fn() + } as jest.MockedObject; + }); + + describe("constructor", () => { + let multiThreadedSubscriber: ExtendedBlockSubscription; + + test("must create as many workers as number of RPC urls passed", () => { + multiThreadedSubscriber = new ExtendedBlockSubscription( + mockedEthObject, + ["mock_endpoint", "mock_endpoint", "mock_endpoint"], + 0, + "block_getter" + ); + expect(mockedWorkerClass).toBeCalledTimes(3); + }); + + test("must not create workers if no RPC passed.", () => { + multiThreadedSubscriber = new ExtendedBlockSubscription( + mockedEthObject, + [], + 0, + "block_getter" + ); + expect(mockedWorkerClass).toBeCalledTimes(0); + }); + + test("if one of workers exit, new one must be created in their place.", () => { + multiThreadedSubscriber = new ExtendedBlockSubscription( + mockedEthObject, + ["mock_endpoint"], + 0, + "block_getter" + ); + const mockedWorker: jest.MockedObject = mockedWorkerClass.mock.instances[0] as jest.MockedObject; + mockedWorker.on.mock.calls[0][1](); + + expect(mockedWorkerClass).toBeCalledTimes(2); + }); + + test("Must create the worker with right default params", () => { + multiThreadedSubscriber = new ExtendedBlockSubscription( + mockedEthObject, + ["mock_endpoint"], + undefined, + undefined + ); + + expect(mockedWorkerClass).toBeCalledWith( + require.resolve("../../dist/internal/block_getters/block_getter_worker"), + { + workerData: { + endpoint: "mock_endpoint", + maxRetries: 0 + } + } + ); + }); + }); + + describe("getBlockFromWorker", () => { + let mockedFirstWorker: jest.MockedObject, + mockedThirdWorker: jest.MockedObject, + multiThreadedSubscriber: ExtendedBlockSubscription; + + beforeEach(() => { + multiThreadedSubscriber = new ExtendedBlockSubscription( + mockedEthObject, + ["mock_endpoint", "mock_endpoint", "mock_endpoint"], + 0, + "block_getter" + ); + mockedFirstWorker = mockedWorkerClass.mock.instances[0] as jest.MockedObject; + mockedThirdWorker = mockedWorkerClass.mock.instances[2] as jest.MockedObject; + }); + + test("must post message to the right worker as per worker Id", async () => { + mockedThirdWorker.on.mockImplementationOnce((event, listener) => { + if (event === 'message') { + setImmediate(() => { + //TODO - Mock the callBackId set so test does not fail here. + listener({ + callBackId: mockedThirdWorker.postMessage.mock.calls[0][0].callBackId, + block: fullEthereumBlock + }); + }); + }; + + return mockedThirdWorker; + }); + + await multiThreadedSubscriber.getBlockFromWorker(0, 2); + + expect(mockedThirdWorker.postMessage).toBeCalledWith({ + blockNumber: 0, + callBackId: expect.anything() + }); + expect(mockedFirstWorker.postMessage).not.toBeCalled(); + }); + + test("must resolve with block returned by worker.", async () => { + mockedThirdWorker.on.mockImplementationOnce((event, listener) => { + if (event === 'message') { + setImmediate(() => { + listener({ + callBackId: mockedThirdWorker.postMessage.mock.calls[0][0].callBackId, + block: fullEthereumBlock + }); + }); + }; + + return mockedThirdWorker; + }); + + await expect( + multiThreadedSubscriber.getBlockFromWorker(0, 2) + ).resolves.toEqual({ + block: fullEthereumBlock, + error: null + }); + }); + + test("must resolve with error object if worker returns error for that block", async () => { + mockedThirdWorker.on.mockImplementationOnce((event, listener) => { + setImmediate(() => { + //TODO - Mock the callBackId set so test does not fail here. + listener({ + callBackId: mockedThirdWorker.postMessage.mock.calls[0][0].callBackId, + error: new Error("mock") + }); + }); + return mockedThirdWorker; + }); + + await expect( + multiThreadedSubscriber.getBlockFromWorker(0, 2) + ).resolves.toEqual( + expect.objectContaining({ + error: new Error("mock") + }) + ); + }); + + test("must reject error with if worker exits", async () => { + mockedThirdWorker.on.mockImplementationOnce((event, listener) => { + return mockedThirdWorker; + }); + mockedThirdWorker.on.mockImplementationOnce((event, listener) => { + if (event === 'error') { + listener(new Error("mock")); + }; + + return mockedThirdWorker; + }); + + await expect( + multiThreadedSubscriber.getBlockFromWorker(0, 2) + ).resolves.toEqual( + expect.objectContaining({ + error: new Error("mock") + }) + ); + }); + }); + + describe("backfill", () => { + let mockedWorker: jest.MockedObject, + subscriber: ExtendedBlockSubscription; + + beforeEach(() => { + subscriber = new ExtendedBlockSubscription( + mockedEthObject, + ["mock_endpoint"], + 0, + "block_getter" + ); + + mockedWorker = mockedWorkerClass.mock.instances[0] as jest.MockedObject; + mockedWorker.on.mockReset(); + }); + + test("Backfilling must stop if unsubscribe has been called.", (done) => { + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 51 } as BlockTransactionObject); + mockedWorker.on.mockImplementation((event, listener) => { + if (event === 'message') { + setImmediate(() => { + //TODO - Mock the callBackId set so test does not fail here. + listener({ + callBackId: mockedWorker.postMessage.mock.calls[0][0].callBackId, + block: fullEthereumBlock + }); + }); + setImmediate(() => done()) + }; + + return mockedWorker; + }); + subscriber.subscribe(observer, 0).then(() => { + subscriber.unsubscribe(); + }); + + expect(observer.next).not.toBeCalled(); + }); + + test("Backfilling must call next with full block data upto finalized block", (done) => { + expect.assertions(52); + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 51 } as BlockTransactionObject); + let nextBlock: number = 0; + mockedWorker.on.mockImplementation((event, listener) => { + if (event === 'message') { + setImmediate(() => { + //TODO - Mock the callBackId set so test does not fail here. + listener({ + callBackId: mockedWorker.postMessage.mock.calls[nextBlock][0].callBackId, + block: fullEthereumBlock + }); + nextBlock++ + }); + }; + + return mockedWorker; + }); + + let eventNumber: number = 0; + subscriber.subscribe({ + next: async (block: IBlock) => { + eventNumber++; + expect(block).toEqual(fullEthereumBlock); + if (eventNumber >= 52) { + done(); + } + }, + error: observer.error, + closed: observer.closed + }, + 0 + ); + + }); + + test("Backfilling must call next with full block data in order even with order of promises changed upto finalized block", (done) => { + expect.assertions(52); + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 51 } as BlockTransactionObject); + let nextBlock: number = 0; + mockedWorker.on.mockImplementationOnce((event, listener) => { + if (event === 'message') { + const callNumber = nextBlock; + setImmediate(() => { + listener({ + callBackId: 123, + block: fullEthereumBlock + }); + + listener({ + callBackId: mockedWorker.postMessage.mock.calls[callNumber][0].callBackId, + block: fullEthereumBlock + }); + }); + + nextBlock++ + }; + + return mockedWorker; + }); + + mockedWorker.on.mockImplementation((event, listener) => { + if (event === 'message') { + const callNumber = nextBlock; + setImmediate(() => { + //TODO - Mock the callBackId set so test does not fail here. + listener({ + callBackId: mockedWorker.postMessage.mock.calls[callNumber][0].callBackId, + block: fullEthereumBlock + }); + }); + + nextBlock++ + }; + + return mockedWorker; + }); + + let eventNumber: number = 0; + subscriber.subscribe({ + next: async (block: IBlock) => { + eventNumber++; + expect(block).toEqual(fullEthereumBlock); + if (eventNumber >= 52) { + done(); + } + }, + error: observer.error, + closed: observer.closed + }, + 0 + ); + + }); + + test("On error while backfilling, observer.error must be called with block producer error", (done) => { + expect.assertions(2); + + mockedEthObject.getBlock.mockResolvedValueOnce({ number: 51 } as BlockTransactionObject); + mockedWorker.on.mockImplementationOnce((event, listener) => { + if (event === 'error') { + listener( + new Error("Mock") + ); + }; + + return mockedWorker; + }); + mockedWorker.on.mockImplementationOnce((event, listener) => { + if (event === 'error') { + listener( + new Error("Mock") + ); + }; + + return mockedWorker; + }); + + subscriber.subscribe(observer, 0); + + setImmediate(() => { + expect(observer.error).toBeCalledTimes(1); + expect(observer.error).toBeCalledWith( + BlockProducerError.createUnknown( + new Error("Mock") + ) + ); + done() + }); + }); + }); +}); diff --git a/tests/coder/abi_coder.test.ts b/tests/coder/abi_coder.test.ts new file mode 100644 index 0000000..aa6fe03 --- /dev/null +++ b/tests/coder/abi_coder.test.ts @@ -0,0 +1,70 @@ +import { ABICoder } from "../../dist/internal/coder/abi_coder"; +import AbiCoder from "web3-eth-abi"; + +jest.mock("web3-eth-abi"); + +describe("abi_coder", () => { + let abiCoderObject: jest.MockedObject + + beforeEach(() => { + abiCoderObject = AbiCoder as jest.MockedObject; + }); + + describe("ABICoder", () => { + test("decodeParameter", () => { + //@ts-ignore + abiCoderObject.decodeParameter.mockReturnValueOnce("mocked_result") + expect( + ABICoder.decodeParameter( + "mocked_type", + "mocked_input" + ) + ).toEqual("mocked_result") + }); + + test("decodeParameters", () => { + //@ts-ignore + abiCoderObject.decodeParameters.mockReturnValueOnce(["mocked_result"]) + expect( + ABICoder.decodeParameters( + ["mocked_type"], + "mocked_input" + ) + ).toEqual(["mocked_result"]) + }); + + test("encodeParameters", () => { + //@ts-ignore + abiCoderObject.encodeParameters.mockReturnValueOnce("mocked_result") + expect( + ABICoder.encodeParameters( + ["mocked_type"], + ["mocked_value"] + ) + ).toEqual("mocked_result") + }); + + test("decodeLog", () => { + //@ts-ignore + abiCoderObject.decodeLog.mockReturnValueOnce(["mocked_result"]) + expect( + ABICoder.decodeLog( + ["mocked_input"], + "mocked_hex", + ["mocked_topics"] + ) + ).toEqual(["mocked_result"]) + }); + + test("decodeMethod", () => { + //@ts-ignore + abiCoderObject.decodeParameters.mockReturnValueOnce(["mocked_result"]) + expect( + ABICoder.decodeMethod( + ['bytes'], + "mocked_input_data" + ) + ).toEqual(["mocked_result"]) + }); + }); +}); diff --git a/tests/coder/protobuf_coder.test.ts b/tests/coder/protobuf_coder.test.ts new file mode 100644 index 0000000..dba0d9d --- /dev/null +++ b/tests/coder/protobuf_coder.test.ts @@ -0,0 +1,153 @@ +import { CoderError } from "../../dist/internal/errors/coder_error"; +import { Coder } from "../../dist/internal/coder/protobuf_coder"; +import Long from "long"; +import protobufjs, { Type, Root, Writer, Message } from "protobufjs"; + +jest.mock("protobufjs"); + + +describe("Protobuf Coder", () => { + let coder: Coder, + protobuf: jest.Mocked, + protobufType: jest.Mocked, + protobufRoot: jest.Mocked, + protobufWriter: jest.Mocked; + + const mockBuffer: Buffer = Buffer.from( + [0x08, 0xbb, 0xaa, 0x8e, 0x88, 0xe8, 0x9e, 0x84, 0x91, 0x11, 0x12, 0x04, 0x64, 0x65, 0x6d, 0x6f] + ); + const mockMessageObject = { + number: Long.fromValue("1234567898765432123", true), + string: "demo" + }; + + beforeEach(() => { + protobuf = protobufjs as jest.Mocked; + protobufType = new Type("Block") as jest.Mocked; + protobufRoot = new Root() as jest.Mocked; + protobufWriter = new Writer() as jest.Mocked; + coder = new Coder("test", "testpackage", "Test"); + + protobuf.load.mockResolvedValue(protobufRoot); + protobufRoot.lookupType.mockReturnValue(protobufType); + }); + + describe("serialize()", () => { + test("Must return serialised buffer", async () => { + protobufType.encode.mockReturnValueOnce(protobufWriter); + protobufWriter.finish.mockReturnValueOnce(mockBuffer); + + await expect( + coder.serialize(mockMessageObject) + ).resolves.toEqual(mockBuffer); + expect(protobufType.verify).toBeCalledWith(mockMessageObject); + expect(protobufType.encode).toBeCalledWith(mockMessageObject); + expect(protobufWriter.finish).toBeCalled(); + }); + + test("On failure to find schema coder error must be thrown", async () => { + protobuf.load.mockRejectedValueOnce( + new Error( + "no such type: wrongpackage.Test" + ) + ); + + await expect( + coder.serialize(mockMessageObject) + ).rejects.toEqual( + new CoderError( + "Coder error", + CoderError.codes.INVALID_PATH_PROTO, + true, + "no such type: wrongpackage.Test" + ) + ); + }); + + test("On failure to verify message as per schema, verification error must be thrown", + async () => { + protobufType.verify.mockReturnValueOnce( + "string: string expected" + ); + + await expect(coder.serialize({ + number: 123, + wrongField: "demo" + })).rejects.toEqual( + new CoderError( + "Message verification failed", + CoderError.codes.ENCODING_VERIFICATION_FAILED, + false, + "string: string expected" + )); + }); + }); + + describe("deserialize()", () => { + test("Must return deserialised object", async () => { + protobufType.decode.mockReturnValueOnce( + mockMessageObject as unknown as Message + ); + + await expect( + coder.deserialize(mockBuffer) + ).resolves.toEqual(mockMessageObject); + expect(protobufType.decode).toBeCalledWith(mockBuffer); + }); + + test("On failure to find schema coder error must be thrown", async () => { + protobuf.load.mockRejectedValueOnce( + new Error( + "no such type: wrongpackage.Test" + ) + ); + + await expect( + coder.deserialize(mockBuffer) + ).rejects.toEqual( + new CoderError( + "Coder error", + CoderError.codes.INVALID_PATH_PROTO, + true, + "no such type: wrongpackage.Test" + ) + ); + }); + + test("On failure to deserialise message as per schema, decoding error must be thrown", + async () => { + protobufType.decode.mockImplementationOnce(() => { + throw new Error("invalid wire type 4 at offset 4"); + }); + + await expect( + coder.deserialize(Buffer.from( + [0x09, 0x8b, 0x12, 0x04, 0x64, 0x65, 0x6d, 0x6f] + )) + ).rejects.toEqual( + new CoderError( + "Decoding error", + CoderError.codes.DECODING_ERROR, + true, + "invalid wire type 4 at offset 4" + ) + ); + }); + }); + + describe("custom loadType: schemaPath", () => { + test("Must accept custom schemaPath", async () => { + + const customCoder = new Coder("test", "testpackage", "Test", "open-api-common/schemas") + + protobufType.decode.mockReturnValueOnce( + mockMessageObject as unknown as Message + ); + + await expect( + customCoder.deserialize(mockBuffer) + ).resolves.toEqual(mockMessageObject); + expect(protobufType.decode).toBeCalledWith(mockBuffer); + }); + }); +}); diff --git a/tests/errors/api_error.test.ts b/tests/errors/api_error.test.ts new file mode 100644 index 0000000..e600f40 --- /dev/null +++ b/tests/errors/api_error.test.ts @@ -0,0 +1,137 @@ +import { createErrorObject } from "../../dist/internal/errors/create_error_object"; +import { isBaseError } from "../../dist/internal/errors/is_base_error"; +import { BaseError } from "../../dist/internal/errors/base_error"; +import { ApiError } from "../../dist/internal/errors/api_error"; + +jest.mock("../../dist/internal/errors/base_error"); +jest.mock("../../dist/internal/errors/is_base_error"); +jest.mock("../../dist/internal/errors/create_error_object"); + +describe("ApiError", () => { + let apiError: ApiError, + mockedBaseErrorInstance: jest.MockedObject, + mockedBaseErrorClass: jest.MockedClass, + mockedIsBaseError: jest.MockedFunction, + mockedCreateErrorObject: jest.MockedFunction; + + beforeEach(() => { + apiError = new ApiError(); + mockedBaseErrorClass = BaseError as jest.MockedClass; + mockedIsBaseError = isBaseError as jest.MockedFunction; + mockedCreateErrorObject = createErrorObject as jest.MockedFunction; + mockedBaseErrorInstance = mockedBaseErrorClass.mock.instances[0] as jest.MockedObject; + }); + + describe("Api error class", () => { + test("Api error object by default must have 'Api error' as name set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + "Internal server error", + expect.anything(), + expect.anything(), + undefined, + "local", + undefined + ); + } + ); + + test("Api error object by default must have 500 as error code set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + expect.anything(), + 500, + expect.anything(), + undefined, + expect.anything(), + undefined + ); + } + ); + + test("Api error class must have a static property codes which is an object of all block producer codes", + () => { + expect(ApiError.codes).toEqual({ + BASE_ERROR: 100, + BAD_REQUEST: 400, + NOT_FOUND: 404, + SERVER_ERROR: 500 + }); + } + ); + }); + + describe("createUnknown", () => { + test("static method must return error as is, if an instance of base error", + () => { + mockedIsBaseError.mockReturnValue(true); + + expect(ApiError.createUnknown(apiError)).toBe(apiError); + } + ); + + test("static method must convert any unknown error type to error object by calling createErrorObject", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + + expect(ApiError.createUnknown("mock")).toBeInstanceOf(ApiError); + expect(mockedCreateErrorObject).toHaveBeenCalledWith("mock"); + } + ); + + test("static method must set error message to be message of the created error object from unknown", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + ApiError.createUnknown("mock"); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + "mock", + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must set origin to 'local' if isLocal is true", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + ApiError.createUnknown(new Error("mock"), true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + "local", + expect.anything() + ); + } + ); + + test("static method must set origin to 'remote' if isLocal is false", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + ApiError.createUnknown(new Error("mock"), false); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + "remote", + expect.anything() + ); + } + ); + }); +}); diff --git a/tests/errors/base_error.test.ts b/tests/errors/base_error.test.ts new file mode 100644 index 0000000..25854f1 --- /dev/null +++ b/tests/errors/base_error.test.ts @@ -0,0 +1,48 @@ +import { BaseError } from "../../dist/internal/errors/base_error"; + +describe("BaseError", () => { + let baseErrorCodes: { BASE_ERROR: number}; + + beforeEach(() => { + baseErrorCodes = { BASE_ERROR: 100 }; + }); + + test("BaseError.message must be name of the error if the message is not passed.", + () => { + expect(new BaseError("mock", 123).message).toBe("mock"); + } + ); + + test("BaseError must have static property codes with error codes related to BaseError", + () => { + expect(BaseError.codes).toEqual(baseErrorCodes); + } + ); + + test("BaseError must have unique identifier to identify all base errors", + () => { + expect(new BaseError("mock", 123).identifier).toEqual(baseErrorCodes.BASE_ERROR); + } + ); + + test("BaseError.message must be message passed to constructor", + () => { + expect(new BaseError("mock", 123, false, "mock message").message).toBe("mock message"); + } + ); + + test("Base error stack must be the stack passed to the constructor if passed", + () => { + expect( + new BaseError( + "mock", + 123, + false, + "mock message", + "local", + "mock error stack" + ).stack + ).toBe("mock error stack"); + } + ); +}); diff --git a/tests/errors/block_producer_error.test.ts b/tests/errors/block_producer_error.test.ts new file mode 100644 index 0000000..552b7e0 --- /dev/null +++ b/tests/errors/block_producer_error.test.ts @@ -0,0 +1,138 @@ +import { BlockProducerError } from "../../dist/internal/errors/block_producer_error"; +import { createErrorObject } from "../../dist/internal/errors/create_error_object"; +import { isBaseError } from "../../dist/internal/errors/is_base_error"; +import { BaseError } from "../../dist/internal/errors/base_error"; + +jest.mock("../../dist/internal/errors/base_error"); +jest.mock("../../dist/internal/errors/is_base_error"); +jest.mock("../../dist/internal/errors/create_error_object"); + +describe("Block Producer Error", () => { + let blockProducerError: BlockProducerError; + let mockedBaseErrorInstance: jest.MockedObject; + let mockedBaseErrorClass: jest.MockedClass; + let mockedIsBaseError: jest.MockedFunction; + let mockedCreateErrorObject: jest.MockedFunction; + + + beforeEach(() => { + blockProducerError = new BlockProducerError(); + mockedBaseErrorClass = BaseError as jest.MockedClass; + mockedIsBaseError = isBaseError as jest.MockedFunction; + mockedCreateErrorObject = createErrorObject as jest.MockedFunction; + mockedBaseErrorInstance = mockedBaseErrorClass.mock.instances[0] as jest.MockedObject; + }); + + describe("Block producer error class", () => { + test("Block producer error object by default must have 'Block producer error' as name set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + "Block producer error", + expect.anything(), + expect.anything(), + undefined, + "local", + undefined + ); + } + ); + + test("Block producer error object by default must have 4000 as error code set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + expect.anything(), + 4000, + expect.anything(), + undefined, + expect.anything(), + undefined + ); + } + ); + + test("Block producer error class must have a static property codes which is an object of all block producer codes", + () => { + expect(BlockProducerError.codes).toEqual({ + BASE_ERROR: 100, + UNKNOWN_ERR: 4000, + RECEIPT_NOT_FOUND: 4001, + OBSERVER_NOT_SET: 4002 + }); + } + ); + }); + + describe("createUnknown", () => { + test("static method must return error as is, if an instance of base error", + () => { + mockedIsBaseError.mockReturnValue(true); + + expect(BlockProducerError.createUnknown(blockProducerError)).toBe(blockProducerError); + } + ); + + test("static method must convert any unknown error type to error object by calling createErrorObject", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + + expect(BlockProducerError.createUnknown("mock")).toBeInstanceOf(BlockProducerError); + expect(mockedCreateErrorObject).toHaveBeenCalledWith("mock"); + } + ); + + test("static method must set error message to be message of the created error object from unknown", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + BlockProducerError.createUnknown("mock"); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + "mock", + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must set origin to 'local' if isLocal is true", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + BlockProducerError.createUnknown(new Error("mock"), true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + "local", + expect.anything() + ); + } + ); + + test("static method must set origin to 'remote' if isLocal is false", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + BlockProducerError.createUnknown(new Error("mock"), false); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + "remote", + expect.anything() + ); + } + ); + }); +}); diff --git a/tests/errors/coder_error.test.ts b/tests/errors/coder_error.test.ts new file mode 100644 index 0000000..530d024 --- /dev/null +++ b/tests/errors/coder_error.test.ts @@ -0,0 +1,69 @@ +import { CoderError } from "../../dist/internal/errors/coder_error"; +import { BaseError } from "../../dist/internal/errors/base_error"; + +jest.mock("../../dist/internal/errors/base_error"); +jest.mock("../../dist/internal/errors/is_base_error"); +jest.mock("../../dist/internal/errors/create_error_object"); + +describe("Coder Error", () => { + let coderError: CoderError; + let mockedBaseErrorClass: jest.MockedClass; + + + beforeEach(() => { + coderError = new CoderError(); + mockedBaseErrorClass = BaseError as jest.MockedClass; + }); + + test("coder error by default must have 'Coder Error' as name set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + "Coder Error", + expect.anything(), + expect.anything(), + undefined, + "local", + undefined + ); + } + ); + + test("coder error by default must have 1000 as error code set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + expect.anything(), + 1000, + expect.anything(), + undefined, + expect.anything(), + undefined + ); + } + ); + + test("coder error must always set origin to 'local'", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + expect.anything(), + expect.anything(), + expect.anything(), + undefined, + "local", + undefined + ); + } + ); + + test("Block producer must have a static property codes which is an object of all block producer codes", + () => { + expect(CoderError.codes).toEqual({ + BASE_ERROR: 100, + UNKNOWN_CODER_ERR: 1000, + INVALID_PATH_PROTO: 1001, + INVALID_PATH_TYPE: 1002, + DECODING_ERROR: 1003, + ENCODING_VERIFICATION_FAILED: 1004 + }); + } + ); +}); diff --git a/tests/errors/create_error_object.test.ts b/tests/errors/create_error_object.test.ts new file mode 100644 index 0000000..4e4d8dd --- /dev/null +++ b/tests/errors/create_error_object.test.ts @@ -0,0 +1,30 @@ +import { createErrorObject } from "../../dist/internal/errors/create_error_object"; + +describe("Errors - create error object", () => { + const tests = [ + 0, + "string", + { + string: "string", + number: 0 + } + ]; + + test("Must return object without modification, if an instance of Error class", + () => { + const error: Error = new Error("demo"); + expect(createErrorObject(error)).toBe(error); + } + ); + + test("Must return object without modification, if an instance of TypeError class", + () => { + const error: TypeError = new TypeError("demo"); + expect(createErrorObject(error)).toBe(error); + } + ); + + tests.forEach((item) => test("Must return error object", () => { + expect(createErrorObject(item)).toBeInstanceOf(Error); + })); +}); diff --git a/tests/errors/event_consumer_error.test.ts b/tests/errors/event_consumer_error.test.ts new file mode 100644 index 0000000..0aeb9b8 --- /dev/null +++ b/tests/errors/event_consumer_error.test.ts @@ -0,0 +1,140 @@ +import { EventConsumerError } from "../../dist/internal/errors/event_consumer_error"; +import { createErrorObject } from "../../dist/internal/errors/create_error_object"; +import { isBaseError } from "../../dist/internal/errors/is_base_error"; +import { BaseError } from "../../dist/internal/errors/base_error"; + +jest.mock("../../dist/internal/errors/base_error"); +jest.mock("../../dist/internal/errors/is_base_error"); +jest.mock("../../dist/internal/errors/create_error_object"); + +describe("Event Consumer Error", () => { + let eventConsumerError: EventConsumerError; + let mockedBaseErrorInstance: jest.MockedObject; + let mockedBaseErrorClass: jest.MockedClass; + let mockedIsBaseError: jest.MockedFunction; + let mockedCreateErrorObject: jest.MockedFunction; + + + beforeEach(() => { + eventConsumerError = new EventConsumerError(); + mockedBaseErrorClass = BaseError as jest.MockedClass; + mockedIsBaseError = isBaseError as jest.MockedFunction; + mockedCreateErrorObject = createErrorObject as jest.MockedFunction; + mockedBaseErrorInstance = mockedBaseErrorClass.mock.instances[0] as jest.MockedObject; + }); + + describe("Event Consumer Error class", () => { + test("Event Consumer Error object by default must have 'Event Consumer Error' as name set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + "Event Consumer Error", + expect.anything(), + expect.anything(), + undefined, + "local", + undefined + ); + } + ); + + test("Event Consumer Error object by default must have 5000 as error code set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + expect.anything(), + 5000, + expect.anything(), + undefined, + expect.anything(), + undefined + ); + } + ); + + test("Event Consumer Error class must have a static property codes which is an object of all block producer codes", + () => { + expect(EventConsumerError.codes).toEqual({ + BASE_ERROR: 100, + UNKNOWN_ERR: 5000, + SAVE_EXECUTE_ERROR: 5001, + MAPPING_ERROR: 5002, + COMMAND_EXECUTE_ERROR: 5003, + INVALID_PARAMS_VALIDATION: 5004 + }); + } + ); + }); + + describe("createUnknown", () => { + test("static method must return error as is, if an instance of base error", + () => { + mockedIsBaseError.mockReturnValue(true); + + expect(EventConsumerError.createUnknown(eventConsumerError)).toBe(eventConsumerError); + } + ); + + test("static method must convert any unknown error type to error object by calling createErrorObject", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + + expect(EventConsumerError.createUnknown("mock")).toBeInstanceOf(EventConsumerError); + expect(mockedCreateErrorObject).toHaveBeenCalledWith("mock"); + } + ); + + test("static method must set error message to be message of the created error object from unknown", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + EventConsumerError.createUnknown("mock"); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + "mock", + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must set origin to 'local' if isLocal is true", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + EventConsumerError.createUnknown(new Error("mock"), true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + "local", + expect.anything() + ); + } + ); + + test("static method must set origin to 'remote' if isLocal is false", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + EventConsumerError.createUnknown(new Error("mock"), false); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + "remote", + expect.anything() + ); + } + ); + }); +}); diff --git a/tests/errors/get_error_message.test.ts b/tests/errors/get_error_message.test.ts new file mode 100644 index 0000000..1697673 --- /dev/null +++ b/tests/errors/get_error_message.test.ts @@ -0,0 +1,19 @@ +import { getErrorMessage } from "../../dist/internal/errors/get_error_message"; + +describe("Errors - get error message", () => { + test("Must return error message when error object is passed", + () => { + expect(getErrorMessage(new Error("demo"))).toBe("demo"); + } + ); + + test("Must return string as error message if passed variable is not instance of Error", + () => { + expect(getErrorMessage("error")).toBe("error"); + expect(getErrorMessage(123)).toBe("123"); + expect(getErrorMessage({ + code: 123 + })).toBe("{\"code\":123}"); + } + ); +}); diff --git a/tests/errors/kafka_error.test.ts b/tests/errors/kafka_error.test.ts new file mode 100644 index 0000000..0e58791 --- /dev/null +++ b/tests/errors/kafka_error.test.ts @@ -0,0 +1,285 @@ +import { KafkaError } from "../../dist/internal/errors/kafka_error"; +import { createErrorObject } from "../../dist/internal/errors/create_error_object"; +import { isBaseError } from "../../dist/internal/errors/is_base_error"; +import { BaseError } from "../../dist/internal/errors/base_error"; +//@ts-ignore +import connectError from "../mock_data/connect_error.json"; +jest.mock("../../dist/internal/errors/base_error"); +jest.mock("../../dist/internal/errors/is_base_error"); +jest.mock("../../dist/internal/errors/create_error_object"); + +describe("Kafka Error", () => { + let kafkaError: KafkaError; + let mockedBaseErrorInstance: jest.MockedObject; + let mockedBaseErrorClass: jest.MockedClass; + let mockedIsBaseError: jest.MockedFunction; + let mockedCreateErrorObject: jest.MockedFunction; + + + beforeEach(() => { + kafkaError = new KafkaError(undefined, 123); + mockedBaseErrorClass = BaseError as jest.MockedClass; + mockedIsBaseError = isBaseError as jest.MockedFunction; + mockedCreateErrorObject = createErrorObject as jest.MockedFunction; + mockedBaseErrorInstance = mockedBaseErrorClass.mock.instances[0] as jest.MockedObject; + }); + + describe("Block producer error class", () => { + test("Block producer error object by default must have 'Kafka Error' as name set via super()", + () => { + expect(mockedBaseErrorClass).toBeCalledWith( + "Kafka Error", + expect.anything(), + expect.anything(), + undefined, + "local", + undefined + ); + } + ); + + test("Block producer error class must have a static property codes which is an object of all block producer codes", + () => { + expect(KafkaError.codes).toEqual({ + BASE_ERROR: 100, + UNKNOWN_CONSUMER_ERR: 2000, + CONSUMER_OBSERVER_INVALID: 2001, + INVALID_CODER_CONFIG: 2002, + UNKNOWN_PRODUCER_ERR: 3000, + DELIVERY_TIMED_OUT: 3001 + }); + } + ); + }); + + describe("createUnknown", () => { + test("static method must return error as is, if an instance of base error", + () => { + mockedIsBaseError.mockReturnValue(true); + + expect(KafkaError.createUnknown(kafkaError)).toBe(kafkaError); + } + ); + + test("If passed variable is an instance of LibrdKafkaError, createErrorObject must not be called", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + KafkaError.createUnknown(connectError); + + expect(mockedCreateErrorObject).not.toHaveBeenCalled(); + expect(BaseError).toHaveBeenCalledTimes(2); + } + ); + + test("static method must convert any unknown error type to error object by calling createErrorObject", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + + expect(KafkaError.createUnknown("mock")).toBeInstanceOf(KafkaError); + expect(mockedCreateErrorObject).toHaveBeenCalledWith("mock"); + } + ); + + test("static method must set error message to be message of the created error object from unknown", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + KafkaError.createUnknown("mock"); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + "mock", + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must set origin to 'local' as unknown errors would be thrown locally", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + KafkaError.createUnknown(new Error("mock"), true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + "local", + expect.anything() + ); + } + ); + + test("static method must error name to 'Kafka consumer error' by default", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + KafkaError.createUnknown(new Error("mock")); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + "Kafka consumer error", + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must error name to 'Kafka producer error' if by default isProducer is set to true", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + KafkaError.createUnknown(new Error("mock"), true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + "Kafka producer error", + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must error code to 2000 by default", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + KafkaError.createUnknown(new Error("mock")); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + 2000, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must error code to 3000 by default if isProducer is set to true", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + mockedCreateErrorObject.mockReturnValueOnce(new Error("mock")); + KafkaError.createUnknown(new Error("mock"), true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + 3000, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + }); + + describe("convertLibError", () => { + test("static method must convert passed LibrdKafkaError to Kafka Error without modifying the fields except name", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + KafkaError.convertLibError(connectError); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + -195, + true, + "Local: Broker transport failure", + "kafka", + "mock stack string" + ); + } + ); + + test("static method must error name to 'Kafka consumer error' by default", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + KafkaError.convertLibError(connectError); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + "Kafka consumer error", + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + + test("static method must error name to 'Kafka producer error' if by default isProducer is set to true", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + KafkaError.convertLibError(connectError, true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + "Kafka producer error", + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + + test("When LibrdKafkaError.code is not available, code must be set to 2000 default", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + const connectErrorCopy = Object.assign({}, connectError); + //@ts-ignore + delete connectErrorCopy.code; + KafkaError.convertLibError(connectErrorCopy); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + 2000, + true, + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + + test("When LibrdKafkaError.code is not available, code must be set to 3000 if isProducer is true", + () => { + mockedIsBaseError.mockReturnValueOnce(false); + const connectErrorCopy = Object.assign({}, connectError); + //@ts-ignore + delete connectErrorCopy.code; + KafkaError.convertLibError(connectErrorCopy, true); + + expect(mockedBaseErrorClass).toHaveBeenNthCalledWith( + 2, + expect.anything(), + 3000, + expect.anything(), + expect.anything(), + expect.anything(), + expect.anything() + ); + } + ); + }); +}); diff --git a/tests/event_consumer/abstract_event_consumer.test.ts b/tests/event_consumer/abstract_event_consumer.test.ts new file mode 100644 index 0000000..5837cf0 --- /dev/null +++ b/tests/event_consumer/abstract_event_consumer.test.ts @@ -0,0 +1,80 @@ +import { AbstractEventConsumer } from "../../dist/internal/event_consumer/abstract_event_consumer"; +import { DeserialisedMessage } from "../../dist/internal/interfaces/deserialised_kafka_message"; +import { SynchronousConsumer } from "../../dist/internal/kafka/consumer/synchronous_consumer"; +import { EventConsumerError } from "../../dist/internal/errors/event_consumer_error"; +import { Logger } from "../../dist/internal/logger/logger"; +import { BaseError } from "../../dist/internal/errors/base_error"; + +jest.mock("../../dist/internal/kafka/consumer/synchronous_consumer"); +jest.mock("../../dist/internal/errors/event_consumer_error"); +jest.mock("../../dist/internal/logger/logger"); + +describe("Abstract Event Consumer", () => { + class EventConsumer extends AbstractEventConsumer { + public onEvent = jest.fn() + } + + let mockedEventConsumerError: jest.MockedClass, + mockedConsumerClass: jest.MockedClass, + mockedLogger: jest.MockedClass, + mockedConsumerObject: jest.MockedObject, + eventConsumer: EventConsumer; + + beforeEach(() => { + mockedEventConsumerError = EventConsumerError as jest.MockedClass; + mockedConsumerClass = SynchronousConsumer as jest.MockedClass; + mockedLogger = Logger as jest.MockedClass; + + eventConsumer = new EventConsumer( + ["mock_topic"], + {}, + {} + ); + mockedConsumerObject = mockedConsumerClass.mock.instances[0] as jest.MockedObject; + }); + + test("must call start on consumer with observer object", async () => { + await eventConsumer.execute(); + + expect(mockedConsumerObject.start).toBeCalledWith({ + next: expect.anything(), + error: expect.anything(), + closed: expect.anything() + }) + }); + + test("on next, must call onEvent method.", async () => { + await eventConsumer.execute(); + await mockedConsumerObject.start.mock.calls[0][0].next({} as DeserialisedMessage); + + expect(eventConsumer.onEvent).toBeCalledWith({}); + }); + + test("If onEvent rejects, EventConsumerError must be thrown", async () => { + //@ts-ignore + mockedEventConsumerError.createUnknown.mockReturnValueOnce({ message: "mock" }); + eventConsumer.onEvent.mockRejectedValueOnce(new Error("mock")); + + await eventConsumer.execute(); + await expect( + mockedConsumerObject.start.mock.calls[0][0].next({} as DeserialisedMessage) + ).rejects.toEqual({ message: "mock" }); + }); + + test("on error, must be logged on logger", async () => { + await eventConsumer.execute(); + mockedConsumerObject.start.mock.calls[0][0].error({} as BaseError); + + expect(mockedLogger.error).toBeCalledWith({}); + }); + + test("on closed, must be logged on logger", async () => { + //@ts-ignore + eventConsumer.topics = ["mock_topic"]; // Small hack to be able to test this also if the abstract class is mocked. + + await eventConsumer.execute(); + mockedConsumerObject.start.mock.calls[0][0].closed(); + + expect(mockedLogger.info).toBeCalledWith(`Consumer stopped for topics ${["mock_topic"]}`); + }); +}); diff --git a/tests/formatters/block_formatter.test.ts b/tests/formatters/block_formatter.test.ts new file mode 100644 index 0000000..6c97b75 --- /dev/null +++ b/tests/formatters/block_formatter.test.ts @@ -0,0 +1,265 @@ +import { formatters } from "web3-core-helpers"; +// @ts-ignore +import LongImport, * as LongClass from "long"; +import transactionReceiptArray from "../mock_data/ethereum_transaction_receipts_array.json"; +import ethereumBlock from "../mock_data/ethereum_block.json"; +import ethereumFullBlock from "../mock_data/ethereum_full_block.json"; +import { BlockFormatter } from "../../dist/internal/formatters/block_formatter"; +import { TransactionReceipt } from "web3-core"; +import { ITransactionReceipt } from "../../dist/internal/interfaces/transaction_receipt"; +import { IWeb3Transaction } from "../../dist/internal/interfaces/web3_transaction"; +import { ITransaction } from "../../dist/internal/interfaces/transaction"; +import { BlockTransactionObject } from "web3-eth"; +import { IRawReceipt } from "../../dist/internal/interfaces/raw_receipt"; +import { IRawTransaction } from "../../dist/internal/interfaces/raw_transaction"; +import { IRawBlock } from "../../dist/internal/interfaces/raw_block"; +import * as utils from "web3-utils"; + +jest.mock("web3-core-helpers"); +jest.mock("web3-utils"); +jest.mock("long"); + +class ExtendBlockFormatter extends BlockFormatter { + public formatRawReceipt(receipt?: IRawReceipt) { + return super.formatRawReceipt(receipt); + } + public formatRawTransactionObject(transaction: IRawTransaction, receipt: ITransactionReceipt) { + return super.formatRawTransactionObject(transaction, receipt); + } + public formatRawBlock(block: IRawBlock, transactions: ITransaction[]) { + return super.formatRawBlock(block, transactions); + } + public formatBlockWithTransactions(block: BlockTransactionObject, transactions: ITransaction[]) { + return super.formatBlockWithTransactions(block, transactions); + } + public formatTransactionObject(transactionObject: IWeb3Transaction, receipt: ITransactionReceipt) { + return super.formatTransactionObject(transactionObject, receipt); + } + public formatTransactionReceipt(transactionReceipt: TransactionReceipt) { + return super.formatTransactionReceipt(transactionReceipt); + } +} + +describe("BlockFormatter", () => { + let mockedFormattersObject: jest.MockedClass, + mockedUtilsObject: jest.MockedObject, + mockedLong: jest.MockedClass, + blockFormatter: ExtendBlockFormatter; + + beforeEach(() => { + mockedUtilsObject = utils as jest.MockedObject; + mockedLong = LongImport as jest.MockedClass; + mockedFormattersObject = formatters as jest.MockedClass; + blockFormatter = new ExtendBlockFormatter(); + + mockedUtilsObject.toHex.mockReturnValue("0x809aa8"); + //@ts-ignore + mockedLong.fromValue.mockReturnValue({ + "high": 0, + "low": 0, + "unsigned": true + }) + }); + + describe("formatTransactionReceipt", () => { + test("must convert to correct types", () => { + expect( + blockFormatter.formatTransactionReceipt(transactionReceiptArray[0] as unknown as TransactionReceipt) + ).toEqual(ethereumFullBlock.transactions[0].receipt); + }); + + test("must not convert effectiveGasPrice if undefined", () => { + expect( + blockFormatter.formatTransactionReceipt( + { + ...(transactionReceiptArray[0]), + effectiveGasPrice: undefined + } as unknown as TransactionReceipt + ) + ).toEqual( + expect.objectContaining({ + ...(ethereumFullBlock.transactions[0].receipt), + effectiveGasPrice: undefined + }) + ); + }); + }); + + describe("formatTransactionObject", () => { + test("must convert to correct types", () => { + expect( + blockFormatter.formatTransactionObject( + ethereumBlock.transactions[0] as unknown as IWeb3Transaction, + ethereumFullBlock.transactions[0].receipt as unknown as ITransactionReceipt + ) + ).toEqual( + expect.objectContaining( + ethereumFullBlock.transactions[0] + ) + ); + }); + + test("must not convert transaction index if null", () => { + expect( + blockFormatter.formatTransactionObject( + { + ...(ethereumBlock.transactions[0]), + transactionIndex: null + } as unknown as IWeb3Transaction, + ethereumFullBlock.transactions[0].receipt as unknown as ITransactionReceipt + ) + ).toEqual( + expect.objectContaining({ + ...(ethereumFullBlock.transactions[0]), + transactionIndex: null + }) + ); + }); + + test("must convert maxFeePerGas and maxPriorityFeePerGas if not null", () => { + expect( + blockFormatter.formatTransactionObject( + { + ...(ethereumBlock.transactions[0]), + maxFeePerGas: "0x809aa8", + maxPriorityFeePerGas: "0x809aa8" + } as unknown as IWeb3Transaction, + ethereumFullBlock.transactions[0].receipt as unknown as ITransactionReceipt + ) + ).toEqual( + expect.objectContaining({ + ...(ethereumFullBlock.transactions[0]), + maxFeePerGas: "0x809aa8", + maxPriorityFeePerGas: "0x809aa8" + }) + ); + }); + + test("must not convert blockNumber if null", () => { + expect( + blockFormatter.formatTransactionObject( + { + ...(ethereumBlock.transactions[0]), + blockNumber: null + } as unknown as IWeb3Transaction, + ethereumFullBlock.transactions[0].receipt as unknown as ITransactionReceipt + ) + ).toEqual( + expect.objectContaining({ + ...(ethereumFullBlock.transactions[0]), + blockNumber: null + }) + ); + }); + }); + + describe("formatBlockWithTransactions", () => { + test("must convert to correct types", () => { + mockedUtilsObject.hexToNumberString.mockReturnValueOnce("mock_number"); + + expect( + blockFormatter.formatBlockWithTransactions( + ethereumBlock as unknown as BlockTransactionObject, + ethereumFullBlock.transactions as unknown as ITransaction[] + ) + ).toEqual( + expect.objectContaining( + ethereumFullBlock + ) + ); + expect(mockedLong.fromValue).toHaveBeenNthCalledWith( + 1, + "mock_number", + true + ); + }); + + test("must convert baseFeePerGas to undefined if value is undefined", () => { + expect( + blockFormatter.formatBlockWithTransactions( + { + ...ethereumBlock, + baseFeePerGas: undefined + } as unknown as BlockTransactionObject, + ethereumFullBlock.transactions as unknown as ITransaction[] + ) + ).toEqual( + expect.objectContaining( + { + ...ethereumFullBlock, + baseFeePerGas: undefined + } + ) + ); + }); + }); + + describe("formatRawReceipt", () => { + test("must convert to correct types", () => { + mockedUtilsObject.hexToNumber.mockReturnValueOnce(1234); + mockedUtilsObject.hexToNumber.mockReturnValueOnce(0); + mockedUtilsObject.hexToNumber.mockReturnValueOnce(1); + mockedUtilsObject.hexToNumber.mockReturnValueOnce(1234); + //@ts-ignore + mockedFormattersObject.outputLogFormatter.mockReturnValueOnce( + transactionReceiptArray[0].logs[0] + ) + + expect( + blockFormatter.formatRawReceipt({ + ...transactionReceiptArray[0], + effectiveGasPrice: "0x809aa8", + status: "0x1" + } as unknown as IRawReceipt) + ).toEqual(ethereumFullBlock.transactions[0].receipt); + expect(utils.hexToNumber).toBeCalledTimes(4); + expect(mockedFormattersObject.outputLogFormatter).toBeCalledTimes(1); + }); + + test("must return void if transaction receipt is undefined", () => { + expect( + blockFormatter.formatRawReceipt(undefined) + ).toEqual(undefined); + }) + }); + + describe("formatRawTransactionObject", () => { + test("must convert to correct types", () => { + //@ts-ignore + mockedFormattersObject.outputTransactionFormatter.mockReturnValueOnce( + ethereumBlock.transactions[0] + ); + + expect( + blockFormatter.formatRawTransactionObject( + {} as IRawTransaction, + ethereumFullBlock.transactions[0].receipt as unknown as ITransactionReceipt + ) + ).toEqual( + expect.objectContaining( + ethereumFullBlock.transactions[0] + ) + ); + }); + }); + + describe("formatRawBlock", () => { + test("must convert to correct types", () => { + //@ts-ignore + mockedFormattersObject.outputBlockFormatter.mockReturnValueOnce( + ethereumBlock + ); + + expect( + blockFormatter.formatRawBlock( + {} as IRawBlock, + ethereumFullBlock.transactions as unknown as ITransaction[] + ) + ).toEqual( + expect.objectContaining( + ethereumFullBlock + ) + ); + }) + }); +}); diff --git a/tests/kafka/consumer/abstract_consumer.test.ts b/tests/kafka/consumer/abstract_consumer.test.ts new file mode 100644 index 0000000..949caa4 --- /dev/null +++ b/tests/kafka/consumer/abstract_consumer.test.ts @@ -0,0 +1,668 @@ + +jest.mock("../../../dist/internal/queue/queue"); +jest.mock("node-rdkafka"); +import { DeserialisedMessage } from "../../../dist/internal/interfaces/deserialised_kafka_message"; +import { KafkaConsumer, LibrdKafkaError, Metadata, MetadataOptions } from "node-rdkafka"; +import { IConsumerQueueObject } from "../../../dist/internal/interfaces/consumer_queue_object"; +import { AbstractConsumer } from "../../../dist/internal/kafka/consumer/abstract_consumer"; +import disconnectedError from "../../mock_data/disconnected_error.json"; +import { KafkaError } from "../../../dist/internal/errors/kafka_error"; +import { CoderError } from "../../../dist/internal/errors/coder_error"; +import { IObserver } from "../../../dist/internal/interfaces/observer"; +import { BaseError } from "../../../dist/internal/errors/base_error"; +import connectError from "../../mock_data/connect_error.json"; +import metadataMock from "../../mock_data/metadata_mock.json"; +import { Coder } from "../../../dist/internal/coder/protobuf_coder"; +import mockMessage from "../../mock_data/mock_message.json"; +//@ts-ignore +import { observer } from "../../__mocks__/observer"; +//@ts-ignore +import { coder } from "../../__mocks__/coder"; +import { Queue } from "../../../dist/internal/queue/queue"; + +describe("Kafka - AbstractConsumer", () => { + class Subclass extends AbstractConsumer { + protected enqueue(message: DeserialisedMessage): IConsumerQueueObject { + return { + message + }; + } + } + + let mockedKafkaConsumer: jest.MockedClass, + mockedQueueClass: jest.MockedClass, + consumer: Subclass, + mockedKafkaConsumerInstance: jest.Mocked, + mockedQueueClassInstance: jest.Mocked>>; + + + const mockTopicName: string = "chainId-137"; + mockedKafkaConsumer = KafkaConsumer as jest.MockedClass; + mockedQueueClass = Queue as jest.MockedClass; + beforeEach(() => { + consumer = new Subclass(mockTopicName, { [mockTopicName]: coder as Coder }); + mockedKafkaConsumerInstance = mockedKafkaConsumer.mock.instances[0] as jest.Mocked; + mockedQueueClassInstance = mockedQueueClass.mock.instances[0] as jest.Mocked>>; + + mockedKafkaConsumerInstance.connect.mockImplementation( + ( + metadataOptions?: MetadataOptions | undefined, + cb?: (err: LibrdKafkaError, data: Metadata) => void + ): KafkaConsumer => { + //@ts-ignore + if (cb) cb(null, metadataMock); + return new KafkaConsumer({}, {}); + } + ); + mockedKafkaConsumerInstance.subscribe.mockReturnThis(); + mockedKafkaConsumerInstance.on.mockReturnThis(); + mockedKafkaConsumerInstance.commitMessage.mockReturnThis(); + mockedKafkaConsumerInstance.listenerCount.mockReturnValue(0); + mockedQueueClassInstance.isEmpty.mockReturnValue(true); + }); + + describe("constructor", () => { + test("should call super with default kafka config and topic config", () => { + consumer = new Subclass( + mockTopicName, + { [mockTopicName]: coder as Coder }, + { + "bootstrap.servers": "localhost:9094", + "event_cb": false, + "topicConfig": { + "auto.offset.reset": "latest", + "consume.callback.max.messages": 10 + } + } + ); + + expect(mockedKafkaConsumer).toHaveBeenNthCalledWith( + 2, + { + "debug": "cgrp", + "bootstrap.servers": "localhost:9094", + "enable.auto.commit": false, + "enable.auto.offset.store": false, + "event_cb": false, + "message.max.bytes": 26214400, + "fetch.message.max.bytes": 26214400, + "queued.max.messages.kbytes": 25000 + }, + { + "auto.offset.reset": "latest", + "consume.callback.max.messages": 10 + }, + ) + }); + + test("If consumer and topic config is passed default config must not be used", () => { + expect(mockedKafkaConsumer).toBeCalledWith( + { + "debug": "cgrp", + "bootstrap.servers": "localhost:9092", + "enable.auto.commit": false, + "enable.auto.offset.store": false, + "event_cb": true, + "message.max.bytes": 26214400, + "fetch.message.max.bytes": 26214400, + "queued.max.messages.kbytes": 25000 + }, + { + "auto.offset.reset": "earliest" as "earliest" | "smallest" | "beginning" | "largest" | "latest" | "end" | "error" | undefined + }, + ) + }); + }); + + describe("createConnection() - successful", () => { + + test("Should return broker metadata on connection", async () => { + expect( + await consumer.createConnection() + ).toBe(metadataMock); + }); + + test("The connectionTimeout value used should be the one passed", async () => { + await new Subclass(mockTopicName, { [mockTopicName]: coder as Coder }, { connectionTimeout: 100 }).createConnection(); + expect( + mockedKafkaConsumer.mock.instances[1].connect + ).toBeCalledWith( + expect.objectContaining( + { timeout: 100 } + ), + expect.anything() + ); + }); + + test("Default connection timeout must be used if not set via constructor.", async () => { + await consumer.createConnection(); + expect( + mockedKafkaConsumerInstance.connect + ).toBeCalledWith( + expect.objectContaining( + { timeout: 10000 } + ), + expect.anything() + ); + }); + + + test("Should wait for first internal connect call, even if startConnection is called twice.", async () => { + //Setting timeout to make connect call asynchronous. + mockedKafkaConsumerInstance.connect.mockImplementationOnce( + ( + metadataOptions?: MetadataOptions | undefined, + cb?: (err: LibrdKafkaError, data: Metadata) => void + ): KafkaConsumer => { + setTimeout(() => { + //@ts-ignore + if (cb) cb(null, metadataMock); + }, 100); + return new KafkaConsumer({}, {}); + } + ); + + consumer.createConnection(); + + expect( + await consumer.createConnection() + ).toBe(metadataMock); + expect(mockedKafkaConsumerInstance.connect).toBeCalledTimes(1); + }); + + test("If consumer already connected, connect() function must not be called.", async () => { + await consumer.createConnection(); + + expect(mockedKafkaConsumerInstance.connect).toBeCalledTimes(1); + expect(await consumer.createConnection()).toBe(metadataMock); + expect(mockedKafkaConsumerInstance.connect).toBeCalledTimes(1); + }); + + test("Should throw error if coder config is not set correctly as per topics", async () => { + const consumerMultipleTopics = new Subclass(["mock1", "mock2"], { "mock2": coder as Coder, "mock3": coder as Coder }); + + await expect(consumerMultipleTopics.createConnection()).rejects.toEqual( + new KafkaError( + "Invalid coder config", + KafkaError.codes.INVALID_CODER_CONFIG, + true, + "Coder config does not match topic names.", + "local" + ) + ); + }); + + test("Should throw error if number of coders is not equal to number of topics", async () => { + const consumerMultipleTopics = new Subclass(["mock1", "mock2"], { "mock2": coder as Coder }); + + await expect(consumerMultipleTopics.createConnection()).rejects.toEqual( + new KafkaError( + "Invalid coder config", + KafkaError.codes.INVALID_CODER_CONFIG, + true, + "Coder configuration is not set for every topic.", + "local" + ) + ); + }); + }); + + describe("createConnection() - errors", () => { + beforeEach(() => { + mockedKafkaConsumerInstance.connect.mockImplementationOnce( + ( + metadataOptions?: MetadataOptions | undefined, + cb?: (err: LibrdKafkaError, data: Metadata) => void + ): KafkaConsumer => { + //@ts-ignore + if (cb) cb(connectError, null); + return new KafkaConsumer({}, {}); + } + ); + }); + + test("Should throw KafkaError on connection failure", async () => { + await expect(consumer.createConnection()).rejects.toEqual( + new KafkaError( + "Kafka consumer connection error", + connectError.code, + connectError.isFatal, + connectError.message, + connectError.origin, + connectError.stack + ) + ); + }); + }); + + + describe("start()", () => { + test("If existing listeners, listeners must be cleared before registering current ones.", + async () => { + mockedKafkaConsumerInstance.listenerCount.mockReturnValueOnce(0); + mockedKafkaConsumerInstance.listenerCount.mockReturnValueOnce(0); + mockedKafkaConsumerInstance.listenerCount.mockReturnValueOnce(1); + + mockedKafkaConsumerInstance.connect.mockImplementationOnce( + ( + metadataOptions?: MetadataOptions | undefined, + cb?: (err: LibrdKafkaError, data: Metadata) => void + ): KafkaConsumer => { + //@ts-ignore + if (cb) cb(null, metadataMock); + return new KafkaConsumer({}, {}); + } + ); + + await consumer.start(observer as IObserver); + expect(mockedKafkaConsumerInstance.removeAllListeners).toBeCalled(); + }); + + test("If no existing listeners, removeAllListeners must not be called.", async () => { + await consumer + .start( + observer as IObserver + ); + + expect(mockedKafkaConsumerInstance.removeAllListeners).not.toBeCalled(); + }); + + + test("If consumer is not connected to broker, connect() must be called, or must be skipped otherwise.", async () => { + await consumer.start(observer as IObserver); + await consumer.start(observer as IObserver); + + expect(mockedKafkaConsumerInstance.connect).toBeCalledTimes(1); + }); + + test("Subscribe and consume method must be called on successful connection", async () => { + await consumer.start(observer as IObserver); + + expect(mockedKafkaConsumerInstance.subscribe).toBeCalledTimes(1); + expect(mockedKafkaConsumerInstance.consume).toBeCalledTimes(1); + }); + + test("Subscribe method must be called with right topic names as parameter when topic passed is string", async () => { + await consumer.start(observer as IObserver); + + expect(mockedKafkaConsumerInstance.subscribe).toBeCalledWith(expect.arrayContaining([mockTopicName])); + }); + + test("Subscribe method must be called with right topic names as parameter when topic passed is an array", async () => { + const consumerMultipleTopics = new Subclass(["mock1", "mock2"], { "mock1": coder as Coder, "mock2": coder as Coder }); + await consumerMultipleTopics.start(observer as IObserver); + + expect(mockedKafkaConsumerInstance.subscribe).toBeCalledWith(expect.arrayContaining(["mock1", "mock2"])); + }); + + test("On subscribe/consume error, start must reject with Kafka error", + async () => { + mockedKafkaConsumerInstance.subscribe.mockImplementationOnce(() => { + throw disconnectedError; + }); + + await expect( + consumer.start(observer as IObserver) + ).rejects.toEqual( + new KafkaError( + "Kafka consumer error", + disconnectedError.code, + disconnectedError.isFatal, + disconnectedError.message, + disconnectedError.origin, + disconnectedError.stack + ) + ); + }); + + test("On unknown subscribe/consume error, start must reject with Kafka error", + async () => { + mockedKafkaConsumerInstance.subscribe.mockImplementationOnce(() => { + throw "demo"; + }); + + await expect( + consumer.start(observer as IObserver) + ).rejects.toEqual( + new KafkaError( + "Kafka consumer error", + KafkaError.codes.UNKNOWN_CONSUMER_ERR, + true, + "demo", + "local" + ) + ); + } + ); + + test("Event listener for event.error, data, and disconnected must be registered.", async () => { + mockedKafkaConsumerInstance.subscribe.mockReturnValueOnce(new KafkaConsumer({}, {})); + await consumer.start(observer); + + expect(mockedKafkaConsumerInstance.on).toHaveBeenNthCalledWith(1, "event.error", expect.anything()); + expect(mockedKafkaConsumerInstance.on).toHaveBeenNthCalledWith(2, "data", expect.anything()); + expect(mockedKafkaConsumerInstance.on).toHaveBeenNthCalledWith(3, "disconnected", expect.anything()); + expect(mockedKafkaConsumerInstance.on).toHaveBeenCalledTimes(3); + }); + + test("on failure to deserialise consumed message, CoderError must be thrown.", + (done) => { + const decodingError = new CoderError( + "Decoding error", + CoderError.codes.DECODING_ERROR, + true, + "decoding error" + ); + + coder.deserialize.mockRejectedValueOnce(decodingError); + + consumer.start({ + next: observer.next as IObserver["next"], + error: (error: KafkaError) => { + expect(error).toBe(decodingError); + done(); + }, + closed: observer.closed + }).then( + () => { + const callback = mockedKafkaConsumerInstance.on.mock.calls[1][1]; + //@ts-ignore + callback({ value: "demo", topic: mockTopicName }); + } + ); + } + ); + + test("On event, next must be called with the Deserialised message", + (done) => { + coder.deserialize.mockResolvedValueOnce("demo"); + mockedQueueClassInstance.isEmpty.mockReturnValueOnce(false); + mockedQueueClassInstance.front.mockReturnValueOnce({ + message: mockMessage as unknown as DeserialisedMessage + }); + + consumer.start({ + next: async (message: object) => { + expect(message).toBe(mockMessage); + expect(observer.error).not.toBeCalled(); + done(); + return; + }, + error: observer.error, + closed: observer.closed + }).then( + () => { + const callback = mockedKafkaConsumerInstance.on.mock.calls[1][1]; + //@ts-ignore + callback(mockMessage); + } + ); + } + ); + + test("On next promise reject, the promise must be retried upto maxRetries before calling error on observer", + (done) => { + let retryCount = -1; + const maxRetries = 5; + const consumerWithCustomConfig = new Subclass( + mockTopicName, + { [mockTopicName]: coder as Coder }, + { maxRetries } + ); + mockedQueueClassInstance = mockedQueueClass.mock.instances[1] as jest.Mocked>>; + mockedQueueClassInstance.isEmpty.mockReturnValue(true); + + coder.deserialize.mockResolvedValueOnce("demo"); + for (let i = 0; i <= maxRetries; i++) { + mockedQueueClassInstance.isEmpty.mockReturnValueOnce(false); + mockedQueueClassInstance.front.mockReturnValueOnce({ + message: mockMessage as unknown as DeserialisedMessage + }); + } + + consumerWithCustomConfig.start({ + next: async () => { + retryCount++; + throw new Error("demo error"); + }, + error: () => { + expect(retryCount).toBe(maxRetries); + done(); + }, + closed: observer.closed + }).then( + () => { + //@ts-ignore + ( + mockedKafkaConsumer.mock.instances[1].on as jest.MockedFunction + ).mock.calls[1][1](mockMessage); + } + ); + } + ); + + test("Error thrown by next promise must be converted to KafkaError", + (done) => { + const maxRetries = 0; + const consumerWithCustomConfig = new Subclass( + mockTopicName, + { [mockTopicName]: coder as Coder }, + { maxRetries } + ); + + coder.deserialize.mockResolvedValueOnce("demo"); + + consumerWithCustomConfig.start({ + next: async () => { + throw new Error("demo"); + }, + error: (error: KafkaError) => { + expect(error.name).toBe("Kafka consumer error"); + expect(error.isFatal).toBe(true); + expect(error.code).toBe(KafkaError.codes.UNKNOWN_CONSUMER_ERR); + done(); + }, + closed: observer.closed + }).then( + () => { + //@ts-ignore + ( + mockedKafkaConsumer.mock.instances[1].on as jest.MockedFunction + ).mock.calls[1][1](mockMessage); + } + ); + } + ); + + test("When commitMessage fails, the observer must be informed and the next event must not be processed", + (done) => { + const maxRetries = 0; + const consumerWithCustomConfig = new Subclass( + mockTopicName, + { [mockTopicName]: coder as Coder }, + { maxRetries } + ); + mockedQueueClassInstance = mockedQueueClass.mock.instances[1] as jest.Mocked>>; + mockedQueueClassInstance.isEmpty.mockReturnValue(true); + + coder.deserialize.mockResolvedValueOnce("demo"); + for (let i = 0; i <= maxRetries + 1; i++) { + mockedQueueClassInstance.isEmpty.mockReturnValueOnce(false); + mockedQueueClassInstance.front.mockReturnValueOnce({ + message: mockMessage as unknown as DeserialisedMessage + }); + } + //Adding a small timeout before next is resolved, + // so as to add the second event to queue before attempting to commit message. + observer.next.mockImplementationOnce(() => { + return new Promise((resolve) => { + setTimeout(resolve, 100); + }); + }); + mockedKafkaConsumerInstance.commitMessage.mockImplementationOnce(() => { + throw disconnectedError; + }); + + consumerWithCustomConfig.start({ + next: observer.next as IObserver["next"], + error: (error: KafkaError) => { + expect(error.name).toBe("Kafka consumer error"); + expect(error.message).toBe(disconnectedError.message); + expect(observer.next).toBeCalledTimes(1); + done(); + }, + closed: observer.closed + }).then( + () => { + const callback = ( + mockedKafkaConsumer.mock.instances[1].on as jest.MockedFunction + ).mock.calls[1][1]; + + //@ts-ignore + callback(mockMessage); + //@ts-ignore + callback(mockMessage); + } + ); + }); + + test("When commitMessage fails, class must retry to commit message upto maxRetry times before calling error on observer.", + (done) => { + const maxRetries = 5; + const consumerWithCustomConfig = new Subclass( + mockTopicName, + { [mockTopicName]: coder as Coder }, + { maxRetries } + ); + mockedQueueClassInstance = mockedQueueClass.mock.instances[1] as jest.Mocked>>; + mockedQueueClassInstance.isEmpty.mockReturnValue(true); + + coder.deserialize.mockResolvedValueOnce("demo"); + for (let i = 0; i <= maxRetries; i++) { + mockedKafkaConsumerInstance.commitMessage.mockImplementationOnce(() => { + throw disconnectedError; + }); + mockedQueueClassInstance.isEmpty.mockReturnValueOnce(false); + mockedQueueClassInstance.front.mockReturnValueOnce({ + message: mockMessage as unknown as DeserialisedMessage + }); + } + + consumerWithCustomConfig.start({ + next: observer.next as IObserver["next"], + error: () => { + expect(mockedKafkaConsumerInstance.commitMessage).toBeCalledTimes(maxRetries + 1); + done(); + }, + closed: observer.closed + }).then( + () => { + //@ts-ignore + ( + mockedKafkaConsumer.mock.instances[1].on as jest.MockedFunction + ).mock.calls[1][1](mockMessage); + } + ); + } + ); + + test("When internal queue exceeds maxBuffer limit, the consumer must be paused.", + (done) => { + const onEventCount: number = 0; + const maxRetries: number = 0; + const maxBufferLength: number = 2; + const consumerWithCustomConfig = new Subclass( + mockTopicName, + { [mockTopicName]: coder as Coder }, + { + maxRetries, + maxBufferLength + } + ); + mockedQueueClassInstance = mockedQueueClass.mock.instances[1] as jest.Mocked>>; + mockedQueueClassInstance.isEmpty.mockReturnValue(true); + + coder.deserialize.mockResolvedValueOnce("demo"); + //Four messages emitted by mocks in test. + mockedQueueClassInstance.isEmpty.mockReturnValueOnce(false); + mockedQueueClassInstance.front.mockReturnValueOnce({ + message: mockMessage as unknown as DeserialisedMessage + }); + mockedQueueClassInstance.getLength.mockReturnValueOnce(2); + mockedQueueClassInstance.getLength.mockReturnValueOnce(1); + + consumerWithCustomConfig.start({ + next: async () => { + expect(mockedKafkaConsumerInstance.pause).toBeCalled(); + expect(observer.error).not.toBeCalled(); + done(); + }, + error: observer.next, + closed: observer.closed + }).then( + async () => { + const callback = mockedKafkaConsumerInstance.on.mock.calls[1][1]; + //@ts-ignore + callback(mockMessage); + } + ); + } + ); + + test("A paused consumer must be resumed when buffer length decreases", + (done) => { + const maxRetries: number = 0; + const maxBufferLength: number = 2; + const consumerWithCustomConfig = new Subclass( + mockTopicName, + { [mockTopicName]: coder as Coder }, + { + maxRetries, + maxBufferLength + } + ); + mockedQueueClassInstance = mockedQueueClass.mock.instances[1] as jest.Mocked>>; + mockedQueueClassInstance.isEmpty.mockReturnValue(true); + + coder.deserialize.mockResolvedValueOnce("demo"); + //Four messages emitted by the mock of test. + mockedQueueClassInstance.isEmpty.mockReturnValueOnce(false); + mockedQueueClassInstance.front.mockReturnValueOnce({ + message: mockMessage as unknown as DeserialisedMessage + }); + mockedQueueClassInstance.isEmpty.mockReturnValueOnce(false); + mockedQueueClassInstance.front.mockReturnValueOnce({ + message: mockMessage as unknown as DeserialisedMessage + }); + mockedQueueClassInstance.getLength.mockReturnValueOnce(2); + mockedQueueClassInstance.getLength.mockReturnValueOnce(1); + mockedQueueClassInstance.getLength.mockReturnValueOnce(0); + mockedQueueClassInstance.getLength.mockReturnValueOnce(0); + + let messageCount = 0; + consumerWithCustomConfig.start({ + next: async () => { + messageCount++; + if (messageCount > 1) { + expect(mockedKafkaConsumer.mock.instances[1].resume).toBeCalled(); + done(); + } + }, + error: observer.next, + closed: observer.closed + }).then( + async () => { + const callback = ( + mockedKafkaConsumer.mock.instances[1].on as jest.MockedFunction + ).mock.calls[1][1]; + + //@ts-ignore + callback(mockMessage); + //@ts-ignore + callback(mockMessage); + } + ); + } + ); + }); +}); diff --git a/tests/kafka/consumer/asynchronous_consumer.test.ts b/tests/kafka/consumer/asynchronous_consumer.test.ts new file mode 100644 index 0000000..a866e92 --- /dev/null +++ b/tests/kafka/consumer/asynchronous_consumer.test.ts @@ -0,0 +1,131 @@ +jest.mock("../../../dist/internal/errors/kafka_error"); +jest.mock("../../../dist/internal/kafka/consumer/abstract_consumer"); +import { DeserialisedMessage } from "../../../dist/internal/interfaces/deserialised_kafka_message"; +import { AsynchronousConsumer } from "../../../dist/internal/kafka/consumer/asynchronous_consumer"; +import { IConsumerQueueObject } from "../../../dist/internal/interfaces/consumer_queue_object"; +import { IConsumerConfig } from "../../../dist/internal/interfaces/consumer_config"; +import { IKafkaCoderConfig } from "../../../dist/internal/interfaces/kafka_coder_config"; +import { KafkaError } from "../../../dist/internal/errors/kafka_error"; +import { BaseError } from "../../../dist/internal/errors/base_error"; +import { Coder } from "../../../dist/internal/coder/protobuf_coder"; +import mockMessage from "../../mock_data/mock_message.json"; +//@ts-ignore +import { observer } from "../../__mocks__/observer"; +//@ts-ignore +import { coder } from "../../__mocks__/coder"; + +describe("Kafka - Asynchronous Consumer", () => { + class MockClass extends AsynchronousConsumer { + constructor( + topic: string, + coders: IKafkaCoderConfig, + config: IConsumerConfig = {}, + ) { + super(topic, coders, config); + this.maxRetries = config.maxRetries || config.maxRetries === 0 ? config.maxRetries : 10; + } + public enqueueMock(message: DeserialisedMessage): IConsumerQueueObject { + this.observer = observer; + return this.enqueue(message); + } + } + + let consumer: jest.MockedObject, + mockedKafkaError: jest.MockedClass; + + beforeEach(() => { + consumer = new MockClass( + "chainId-137", + {"chainId-137": coder as unknown as Coder}, + { maxRetries: 0 } + ) as jest.MockedObject; + mockedKafkaError = KafkaError as jest.MockedClass; + }); + + test("Enqueue method must return ConsumerQueueObject with promise", () => { + const object = consumer.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ).promise; + expect(object).toBeInstanceOf(Promise); + }); + + test("On enqueue observer.next must be called with message", async () => { + consumer.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ); + + expect(observer.next).toBeCalledWith(mockMessage); + }); + + test("On observer.next promise reject, promise must throw a converted KafkaError", + async () => { + expect.assertions(2); + //@ts-ignore + mockedKafkaError.createUnknown.mockReturnValue("demo"); + const error = new Error("Demo error"); + observer.next.mockImplementationOnce(async () => { + throw error; + }); + const queueObject = consumer.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ); + + await expect(queueObject.promise).rejects.toBe("demo"); + expect(mockedKafkaError.createUnknown).toHaveBeenCalledWith(error); + } + ); + + test("On observer.next promise reject, promise must be tried upto maxRetry times if not fatal error", + async () => { + expect.assertions(2); + const maxRetries = 5; + for (let i = 0; i <= maxRetries; i++) { + observer.next.mockImplementationOnce(async () => { + throw new Error("Demo"); + }); + } + //@ts-ignore + mockedKafkaError.createUnknown.mockReturnValueOnce("demo"); + + const consumerWithMaxRetries = new MockClass( + "chainId-137", + {"chainId-137": coder as unknown as Coder}, + { maxRetries } + ); + + const queueObject = consumerWithMaxRetries.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ); + + await expect( + queueObject.promise + ).rejects.toEqual("demo"); + expect(observer.next).toBeCalledTimes(maxRetries + 1); + } + ); + + test("On the next promise throwing a fatal error, it must not be retried", + async () => { + expect.assertions(2); + const maxRetries = 5; + observer.next.mockImplementationOnce(async () => { + throw new BaseError("demo", 123, true); + }); + const consumerWithMaxRetries = new MockClass( + "chainId-137", + {"chainId-137": coder as unknown as Coder}, + { maxRetries } + ); + //@ts-ignore + mockedKafkaError.createUnknown.mockReturnValueOnce("demo"); + + const queueObject = consumerWithMaxRetries.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ); + await expect( + queueObject.promise + ).rejects.toEqual("demo"); + expect(observer.next).toBeCalledTimes(1); + } + ); +}); diff --git a/tests/kafka/consumer/synchronous_consumer.test.ts b/tests/kafka/consumer/synchronous_consumer.test.ts new file mode 100644 index 0000000..dcfd189 --- /dev/null +++ b/tests/kafka/consumer/synchronous_consumer.test.ts @@ -0,0 +1,52 @@ +jest.mock("../../../dist/internal/kafka/consumer/abstract_consumer"); +import { IConsumerQueueObject } from "../../../dist/internal/interfaces/consumer_queue_object"; +import { DeserialisedMessage } from "../../../dist/internal/interfaces/deserialised_kafka_message"; +import { SynchronousConsumer } from "../../../dist/internal/kafka/consumer/synchronous_consumer"; +import { Coder } from "../../../dist/internal/coder/protobuf_coder"; +import mockMessage from "../../mock_data/mock_message.json"; +//@ts-ignore +import { observer } from "../../__mocks__/observer"; +//@ts-ignore +import { coder } from "../../__mocks__/coder"; + +jest.mock("node-rdkafka"); + + +describe("Kafka - Synchronous Consumer", () => { + class MockClass extends SynchronousConsumer { + public enqueueMock(message: DeserialisedMessage): IConsumerQueueObject { + this.observer = observer; + return this.enqueue(message); + } + } + + let consumer: MockClass; + + beforeEach(() => { + consumer = new MockClass("chainId-137", {"chainId-137": coder as unknown as Coder}); + }); + + test("Enqueue method must return ConsumerQueueObject without promise", () => { + expect( + consumer.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ).promise + ).toBeFalsy(); + }); + + test("Enqueue method must return ConsumerQueueObject without modifying kafka message", () => { + expect( + consumer.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ).message + ).toBe(mockMessage); + }); + + test("On enqueue observer.next must not be called", async () => { + consumer.enqueueMock( + mockMessage as unknown as DeserialisedMessage + ); + + expect(observer.next).not.toBeCalled(); + }); +}); diff --git a/tests/kafka/producer/abstract_producer.test.ts b/tests/kafka/producer/abstract_producer.test.ts new file mode 100644 index 0000000..f62615c --- /dev/null +++ b/tests/kafka/producer/abstract_producer.test.ts @@ -0,0 +1,284 @@ +import { Producer, LibrdKafkaError, Metadata, ClientMetrics, MetadataOptions, NumberNullUndefined } from "node-rdkafka"; +import { AbstractProducer } from "../../../dist/internal/kafka/producer/abstract_producer"; +import disconnectedError from "../../mock_data/disconnected_error.json"; +import { KafkaError } from "../../../dist/internal/errors/kafka_error"; +import { CoderError } from "../../../dist/internal/errors/coder_error"; +import connectError from "../../mock_data/connect_error.json"; +import metadataMock from "../../mock_data/metadata_mock.json"; +//@ts-ignore +import { coder } from "../../__mocks__/coder"; +import { jest } from "@jest/globals"; + +jest.mock("node-rdkafka"); +describe("Kafka - Producer", () => { + class Subclass extends AbstractProducer { + async produceEvent() { } + } + + let mockedProducer = Producer as jest.MockedClass, + producer: Subclass, + mockedProducerInstance: jest.MockedObject; + + beforeEach(() => { + producer = new Subclass(coder, { topic: "apps.5.pos.bridge.block" }); + mockedProducerInstance = mockedProducer.mock.instances[0]; + + mockedProducerInstance.produce.mockResolvedValue(true); + mockedProducerInstance.flush.mockReturnThis(); + mockedProducerInstance.connect.mockImplementation( + ( + metadataOptions?: MetadataOptions | undefined, + cb?: (err: LibrdKafkaError, data: Metadata) => void + ): Producer => { + //@ts-ignore + if (cb) cb(null, metadataMock); + return new Producer({}); + } + ); + //@ts-ignore + mockedProducerInstance.on = jest.fn().mockReturnThis(); + }); + + describe("start() - successful", () => { + test("Should return broker metadata on connection", async () => { + const metadata = await producer.start(); + expect(metadata).toStrictEqual(metadataMock); + }); + + test("Default connection timeout must be used if not set via constructor.", async () => { + await producer.start(); + expect(mockedProducerInstance.connect.mock.calls[0][0]).toEqual({ timeout: 10000 }); + }); + + test("If connection timeout is passed to constructor, the passed value must be used to connect to kafka instead of default.", async () => { + const producerWithConnectionTimeout = new Subclass(coder, { connectionTimeout: 100 }); + const secondMockedProducerInstance = mockedProducer.mock.instances[1] as jest.MockedObject; + //@ts-ignore + secondMockedProducerInstance.on = jest.fn().mockReturnThis(); + + await producerWithConnectionTimeout.start(); + expect(secondMockedProducerInstance.connect).toBeCalledWith({ timeout: 100 }, expect.anything()); + }); + + test("Should wait for first internal connect call, even if startConnection is called twice.", async () => { + //Setting timeout to make connect call asynchronous. + mockedProducerInstance.connect.mockImplementationOnce( + ( + metadataOptions?: MetadataOptions | undefined, + cb?: (err: LibrdKafkaError, data: Metadata + ) => void + ): Producer => { + setTimeout(() => { + //@ts-ignore + if (cb) cb(null, metadataMock); + }, 100); + return new Producer({}); + } + ); + + producer.start(); + const metadata = await producer.start(); + + expect(mockedProducerInstance.connect).toBeCalledTimes(1); + expect(metadata).toBe(metadataMock); + }); + + test("If producer already connected connect(), function must not be called.", async () => { + await producer.start(); + const metadata = await producer.start(); + + expect(mockedProducerInstance.connect).toBeCalledTimes(1); + expect(metadata).toBe(metadataMock); + }); + }); + + describe("start() - errors", () => { + test("Should return LibRdKafkaError on connection failure", async () => { + mockedProducerInstance.connect.mockImplementationOnce( + ( + metadataOptions?: MetadataOptions | undefined, + cb?: (err: LibrdKafkaError, data: Metadata) => void + ): Producer => { + //@ts-ignore + if (cb) cb(connectError, null); + + return new Producer({}); + } + ); + + await expect(producer.start()).rejects.toEqual( + new KafkaError( + "Kafka consumer error", + connectError.code, + connectError.isFatal, + connectError.message, + connectError.origin, + connectError.stack + ) + ); + }); + }); + + describe("sendToInternalProducer()", () => { + test("Should call connect if client is not connected or skip otherwise", + async () => { + await producer.sendToInternalProducer( + "demo key", + { message: "demo message" }, + "demo" + ); + await producer.sendToInternalProducer( + "demo key2", + { message: "demo message" }, + "demo" + ); + + expect(mockedProducerInstance.connect).toHaveBeenCalledTimes(1); + } + ); + + test("Should return true if successfully produced.", + async () => { + expect( + await producer.sendToInternalProducer( + "demo key", + { message: "demo message" }, + "demo" + ) + ) + .toBe(true); + } + ); + + test("Should throw kafka error if produce returns an error", + async () => { + mockedProducerInstance.produce.mockResolvedValueOnce("demo error string"); + + expect( + producer.sendToInternalProducer( + "demo key", + { message: "demo message" }, + "demo" + ) + ).rejects.toEqual( + KafkaError.createUnknown("demo error string", true) + ); + + } + ); + + test("Should throw coder error if serialising fails", + async () => { + const mockCoderError = new CoderError( + "Invalid proto file path", + CoderError.codes.INVALID_PATH_PROTO, + true, + "demo message"); + coder.serialize.mockRejectedValueOnce(mockCoderError); + + await expect( + producer.sendToInternalProducer( + "demo key", + { message: "demo message" }, + "demo" + ) + ).rejects.toEqual(mockCoderError); + } + ); + + test("On error emitted by Producer client, the error should be emitted to producer.error", + async () => { + await producer.sendToInternalProducer( + "demo key", + { message: "demo message" }, + ); + //@ts-ignore + mockedProducerInstance.on.mock.calls[0][1](connectError, metadataMock); + + expect(mockedProducerInstance.emit).toHaveBeenCalledWith( + "producer.error", + expect.objectContaining( + KafkaError.createUnknown(connectError, true) + ) + ); + } + ); + }); + + describe("stop()", () => { + test("Should resolve to boolean true if disconnected successfully", + async () => { + mockedProducerInstance.disconnect.mockImplementationOnce( + //@ts-ignore + ( + timeout: number, + cb?: (err: LibrdKafkaError, data: ClientMetrics) => void + ) => { + //@ts-ignore + if (cb) cb(undefined, { connectionOpened: 123 }); + return new Producer({}); + } + ); + + await producer.start(); + + expect(await producer.stop()).toEqual(true); + expect(mockedProducerInstance.disconnect).toBeCalled(); + } + ); + + test("On disconnect error if any, kafka error must be thrown", + async () => { + mockedProducerInstance.disconnect.mockImplementationOnce( + ( + timeout: number, + cb?: (err: LibrdKafkaError, data: ClientMetrics) => void + ) => { + if (cb) cb(disconnectedError, { connectionOpened: 123 }); + return new Producer({}); + } + ); + + mockedProducerInstance.flush.mockImplementationOnce( + ( + timeout: NumberNullUndefined, + cb?: (err: LibrdKafkaError, data: ClientMetrics) => void + ) => { + //@ts-ignore + if (cb) cb(undefined, { connectionOpened: 123 }); + return new Producer({}); + } + ); + + await expect( + producer.stop() + ).rejects.toEqual( + KafkaError.convertLibError(disconnectedError as unknown as LibrdKafkaError) + ); + } + ); + + test("Whenever disconnected, producer.disconnected event must be emitted.", + async () => { + await producer.start(); + + //@ts-ignore + mockedProducerInstance.on.mock.calls[1][1](); + expect(mockedProducerInstance.emit).toHaveBeenCalledWith( + "producer.disconnected" + ); + }, + 3000 + ); + + test("On disconnected, all listeners must be removed", + async () => { + await producer.start(); + //@ts-ignore + mockedProducerInstance.on.mock.calls[1][1](); + + expect(mockedProducerInstance.removeAllListeners).toBeCalled(); + } + ); + }); +}); diff --git a/tests/kafka/producer/asynchronous_producer.test.ts b/tests/kafka/producer/asynchronous_producer.test.ts new file mode 100644 index 0000000..859f2a6 --- /dev/null +++ b/tests/kafka/producer/asynchronous_producer.test.ts @@ -0,0 +1,118 @@ +jest.mock("../../../dist/internal/kafka/producer/abstract_producer"); +import { AsynchronousProducer } from "../../../dist/internal/kafka/producer/asynchronous_producer"; +import disconnectedError from "../../mock_data/disconnected_error.json"; +import { ICoder } from "../../../dist/internal/interfaces/coder"; +import { DeliveryReport } from "node-rdkafka"; + +describe("Kafka - Asynchronous Producer", () => { + let producer: jest.Mocked; + + const mockDeliveryReport: DeliveryReport = { + value: Buffer.from("Demo"), + size: 1, + key: Buffer.from("1"), + timestamp: 123, + offset: 0, + topic: "demo", + partition: 0 + }; + + beforeEach(() => { + producer = new AsynchronousProducer({} as unknown as ICoder, { topic: "" }) as jest.Mocked; + + producer.sendToInternalProducer.mockResolvedValue(true); + producer.on.mockReturnThis(); + producer.listenerCount.mockReturnValue(0); + }); + + describe("produceEvent", () => { + test("produceEvent should not wait for delivery report before resolving to true.", + async () => { + expect.assertions(2); + await expect( + producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ) + ).resolves.toBe(true); + + expect(producer.sendToInternalProducer).toHaveBeenNthCalledWith( + 1, + "demo key", + { message: "demo message" }, + "demo", + undefined, + undefined, + undefined + ); + } + ); + + test("produceEvent adds listener for delivery-report if not already added.", + async () => { + expect.assertions(1); + await producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ); + + expect(producer.on).toBeCalledWith( + "delivery-report", + expect.anything() + ); + } + ); + + test("produceEvent does not add listener if delivery-report listener exists.", + async () => { + expect.assertions(2); + //@ts-ignore + producer.listenerCount.mockReturnValueOnce(1); + await producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ); + + expect(producer.on).not.toHaveBeenCalledWith( + "delivery-report", expect.anything() + ); + expect(producer.on).not.toHaveBeenCalledWith(); + } + ); + + test("onDeliveryReport, delivered event must be emitted", + async () => { + expect.assertions(1); + await producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ); + + //@ts-ignore + producer.on.mock.calls[0][1](undefined, mockDeliveryReport); + expect(producer.emit).toHaveBeenLastCalledWith( + "delivered", + mockDeliveryReport + ); + } + ); + + test("onDeliveryReport error, delivered event must not be emitted", + async () => { + expect.assertions(1); + await producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ); + //@ts-ignore + producer.on.mock.calls[0][1](disconnectedError, null); + expect(producer.emit).not.toBeCalledWith("delivered", expect.anything()); + } + ); + }); +}); diff --git a/tests/kafka/producer/synchronous_producer.test.ts b/tests/kafka/producer/synchronous_producer.test.ts new file mode 100644 index 0000000..6598e0a --- /dev/null +++ b/tests/kafka/producer/synchronous_producer.test.ts @@ -0,0 +1,97 @@ +jest.mock("../../../dist/internal/kafka/producer/abstract_producer"); +import { SynchronousProducer } from "../../../dist/internal/kafka/producer/synchronous_producer"; +import { Metadata, ClientMetrics, DeliveryReport } from "node-rdkafka"; +import disconnectedError from "../../mock_data/disconnected_error.json"; +import { KafkaError } from "../../../dist/internal/errors/kafka_error"; +import { ICoder } from "../../../dist/internal/interfaces/coder"; +import { jest } from "@jest/globals"; + + +describe("Kafka - Synchronous Producer", () => { + let producer: jest.Mocked; + const mockDeliveryReport: DeliveryReport = { + value: Buffer.from("Demo"), + size: 1, + key: Buffer.from("1"), + timestamp: 123, + offset: 0, + topic: "demo", + partition: 0 + }; + + beforeEach(() => { + producer = new SynchronousProducer({} as unknown as ICoder, { deliveryTimeout: 500, topic: "" }) as jest.Mocked; + producer.sendToInternalProducer.mockResolvedValue(true); + }); + + describe("produceEvent", () => { + test("produceEvent should reject with error, if delivery report is not available before deliveryTimeout", + async () => { + await expect( + producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ) + ).rejects.toEqual( + new KafkaError( + "Kafka producer error", + KafkaError.codes.DELIVERY_TIMED_OUT, + false, + "Could not receive delivery confirmation before 500 ms", + "remote" + ) + ); + } + ); + + test("produceEvent should wait for delivery report before resolving with the report.", + async () => { + producer.sendToInternalProducer.mockImplementationOnce( + async () => { + mockDeliveryReport.opaque = producer.sendToInternalProducer.mock.calls[0][5]; + producer.on.mock.calls[0][1](null, mockDeliveryReport as DeliveryReport & Metadata & ClientMetrics); + return true; + } + ); + await expect( + producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ) + ).resolves.toBe(mockDeliveryReport); + } + ); + + test("If delivery report reports an error, Kafka error must be thrown.", + async () => { + producer.sendToInternalProducer.mockImplementationOnce( + async () => { + mockDeliveryReport.opaque = producer.sendToInternalProducer.mock.calls[0][5]; + // To make the process async and allow poll to be called before test completes. + // TODO - remove setTimeout to avoid complexity. + setTimeout(() => { + producer.on.mock.calls[0][1]( + disconnectedError, + mockDeliveryReport as DeliveryReport & Metadata & ClientMetrics + ); + }, 150); + + return true; + } + ); + + await expect( + producer.produceEvent( + "demo key", + { message: "demo message" }, + "demo" + ) + ).rejects.toEqual( + KafkaError.convertLibError(disconnectedError) + ); + } + ); + }); +}); diff --git a/tests/logger/logger.test.ts b/tests/logger/logger.test.ts new file mode 100644 index 0000000..f502776 --- /dev/null +++ b/tests/logger/logger.test.ts @@ -0,0 +1,254 @@ +import { Logger } from "../../dist/internal/logger/logger"; +import winston, { Logger as WinstonLogger } from 'winston'; +import SentryImport from "winston-transport-sentry-node"; +//@ts-ignore +const Sentry = SentryImport.default; + +//Have to do below as jest is not able to auto mock exports.default of common js correctly. +jest.mock('winston-transport-sentry-node', () => { + return { + default: jest.fn() + } +}); + +//Manual mocking required as namespace conflicts with methods of same name. +jest.mock("winston", () => { + return { + format: { + timestamp: jest.fn(), + colorize: jest.fn(), + printf: jest.fn(), + combine: jest.fn() + }, + transports: { + Console: jest.fn().mockImplementation(() => { + return {console: true}; + }), + Http: jest.fn().mockImplementation(() => { + return {datadog: true}; + }) + }, + createLogger: jest.fn() + } +}); + +describe("Logger", () => { + let mockedWinston: jest.Mocked, + mockedWinstonFormat: jest.MockedObject, + mockedWinstonTransports: jest.MockedObject, + mockedSentryClass: jest.MockedClass, + mockedSentry: jest.MockedObject; + + let mockedLogger: jest.MockedObject = { + info: jest.fn(), + debug: jest.fn(), + error: jest.fn(), + warn: jest.fn(), + log: jest.fn() + } as jest.MockedObject; + + beforeAll(()=>{ + Logger.create({ + winston: { + level: "error" + }, + sentry: { + dsn: 'test_dsn', + level: 'error', + environment: 'staging' + }, + datadog: { + api_key: 'test_api_key', + service_name: 'test_app_key' + } + }); + }) + + beforeEach(() => { + mockedWinston = winston as jest.Mocked; + mockedWinstonFormat = winston.format as jest.MockedObject; + mockedWinstonTransports = winston.transports; + mockedSentryClass = Sentry as jest.MockedClass; + }); + + test("create - should create logger with passed config or default config otherwise", () => { + const colorizer = { addColors: (colors) => { } } as winston.Logform.Colorizer; + + mockedWinstonFormat.combine.mockReturnValueOnce({format: true} as unknown as winston.Logform.Format); + + mockedWinston.createLogger.mockReturnValueOnce(mockedLogger); + + mockedWinstonFormat.timestamp.mockReturnValueOnce( + { options: {} } as winston.Logform.Format + ); + mockedWinstonFormat.colorize.mockReturnValueOnce(colorizer); + mockedWinstonFormat.printf.mockReturnValueOnce( + {} as winston.Logform.Format + ); + + Logger.create({ + winston: { + level: "error" + }, + sentry: { + dsn: 'test_dsn', + level: 'error', + environment: 'staging' + }, + datadog: { + api_key: 'test_api_key', + service_name: 'test_app_key' + } + }); + + mockedSentry = mockedSentryClass.mock.instances[0] as unknown as jest.MockedObject; + + expect(mockedWinstonFormat.combine).toHaveBeenNthCalledWith( + 1, + { options: {} }, + colorizer, + {} + ); + + //Since this the first time that Logger create is called we verify the first creation of winston logger + expect(mockedWinston.createLogger).toHaveBeenCalledTimes(1); + + expect(mockedWinston.createLogger).toHaveBeenCalledWith( + { + level: 'error', + format: {format: true}, + transports: [ + {console: true}, + mockedSentry, + {datadog: true} + ] + } + ); + + expect(mockedWinstonFormat.timestamp).toHaveBeenNthCalledWith( + 1, + { + format: 'YYYY-MM-DD HH:mm:ss:ms' + } + ); + + expect(mockedWinstonFormat.colorize).toHaveBeenNthCalledWith( + 1, + { + all: true, + colors: { + error: 'red', + warn: 'yellow', + info: 'green', + debug: 'white', + } + } + ); + + expect(mockedWinstonFormat.printf).toHaveBeenCalledTimes(1); + + expect(Sentry).toHaveBeenNthCalledWith( + 1, + { + level: 'error', + sentry: { + dsn: 'test_dsn', + environment: 'staging' + } + } + ); + + expect(mockedWinstonTransports.Http).toHaveBeenNthCalledWith( + 1, + { + host: 'http-intake.logs.datadoghq.com', + path: '/api/v2/logs?dd-api-key=test_api_key&ddsource=nodejs&service=test_app_key', + ssl: true + } + ); + + expect(mockedWinstonTransports.Console).toHaveBeenCalledTimes(1); + }); + + test('Logger is a singleton', () => { + // Create an instance of Logger + Logger.create({ + winston: { + level: "error" + }, + sentry: { + dsn: 'test_dsn2', + level: 'error' , + environment: 'staging' + }, + datadog: { + api_key: 'test_api_key2', + service_name: 'test_app_key' + } + }); + + //Since the test "create - should create logger with passed config or default config otherwise" has already been executed before this test, + //calling Logger create method will not call the createLogger of mockedWinston. Verifying this will serve as our test for Singleton. + expect(mockedWinston.createLogger).toHaveBeenCalledTimes(0); + }); + + test("info must call logger.info with the message passed", () => { + Logger.info("mock"); + + expect(mockedLogger.info).toBeCalledWith("mock"); + }); + + test("info must call logger.info with stringified message of the object", () => { + Logger.info({ mock: "string" }); + + expect(mockedLogger.info).toBeCalledWith(JSON.stringify({ mock: "string" })); + }); + + test("debug must call logger.debug with the message passed", () => { + Logger.debug("mock"); + + expect(mockedLogger.debug).toBeCalledWith("mock"); + }); + + test("debug must call logger.debug with stringified message of the object", () => { + Logger.debug({ mock: "string" }); + + expect(mockedLogger.debug).toBeCalledWith(JSON.stringify({ mock: "string" })); + }); + + test("error must call logger.error with the message passed", () => { + Logger.error("mock"); + + expect(mockedLogger.error).toBeCalledWith("mock"); + }); + + test("error must call logger.error with stringified message of the object", () => { + Logger.error(new Error("mock")); + + expect(mockedLogger.error).toBeCalledWith(`${new Error("mock").message} : ${JSON.stringify(new Error("mock"))}`); + }); + + test("warn must call logger.warn with the message passed", () => { + Logger.warn("mock"); + + expect(mockedLogger.warn).toBeCalledWith("mock"); + }); + + test("warn must call logger.warn with stringified message of the object", () => { + Logger.warn({ mock: "string" }); + + expect(mockedLogger.warn).toBeCalledWith(JSON.stringify({ mock: "string" })); + }); + + test("log must call logger.log with the message passed", () => { + Logger.log("error", "mock"); + + expect(mockedLogger.log).toBeCalledWith("error", "mock"); + }); + + test("log must call logger.log with stringified message of the object", () => { + Logger.log("error", { mock: "string" }); + + expect(mockedLogger.log).toBeCalledWith("error", JSON.stringify({ mock: "string" })); + }); +}); diff --git a/tests/mock_data/block.js b/tests/mock_data/block.js new file mode 100644 index 0000000..dc022b6 --- /dev/null +++ b/tests/mock_data/block.js @@ -0,0 +1,181 @@ +export const blockData = { + baseFeePerGas: 60702551829, + difficulty: "0", + extraData: "0x", + gasLimit: 30000000, + gasUsed: 29855069, + hash: "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + logsBloom: "0x4675688d48cd6d2d31d8cc8fa15082811cf1e1e34801935688e51d855660efd5203c11a84bb08ae552307d59959409fa034c598650123c67c9dc8710023665106848e02bd4382a894e82ca2da818476e925dd669e0f6ebada81ca736ecc01ca22e048310d67eadda59e356c3d8418a540c4113c8c8e94da422b9815224f2a7ecf76a04b4c8b2c000aec9fd5d5440c7b874e32c256b3b81bd8614c8e48b6402d20f57b9b575213b98056579feee25352bd640f39f402280f04331507afe8792c13a52dc1651d029c875121a4adc07fe109b1625650ca6e8b116462d72e248e0a49a55b9db39521f521151b868aa23ab8f621d800b202a42516a40c028511e030e", + miner: "0xf36F155486299eCAff2D4F5160ed5114C1f66000", + mixHash: "0x2ebe643cccae521f1ef76cdcf0589d29cd6a926df466c3e9930a13c74c994f3b", + nonce: "0x0000000000000000", + number: 7951640, + parentHash: "0x7623f3258166598b7a085308557903b461996dd405f77c157572dfcbdbc8168d", + receiptsRoot: "0x629978d8b672729fe57f557c779488e8694cb65d04b50a5bb2be07fee3accff7", + sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + size: 81477, + stateRoot: "0xae398049f42398015accf8037e94a253094a3e72805dc5c33aa4158d9b69fd4f", + timestamp: 1668425976, + totalDifficulty: 10790000, + transactions: [ + { + "hash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b", + "nonce": 2, + "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46", + "blockNumber": 3, + "transactionIndex": 0, + "from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "value": "123450000000000000", + "gas": 314159, + "gasPrice": "2000000000000", + "input": "0x57cb2fc4", + "receipt": { + "blockHash": "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + "blockNumber": 7951640, + "contractAddress": null, + "cumulativeGasUsed": 21510732, + "effectiveGasPrice": 62202551829, + "from": "0xdef24a310c771c570f7511d9ce6ff431e8673e09", + "gasUsed": 193518, + "logs": [ + { + "address": "0x0C93ebAadbDD954bC88EF74A3C4d4c0a85e92e78", + "blockHash": "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + "blockNumber": 7951640, + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000def24a310c771c570f7511d9ce6ff431e8673e0900000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000135f0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": 209, + "removed": false, + "topics": [ + "0x501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b" + ], + "transactionHash": "0x175be54f796aa29a44591aef4b5d4177e82ea2b7f66589ff852725d367e477c5", + "transactionIndex": 104, + "id": "log_6444d866" + }, + { + "address": "0x762d09Ed110ace4EaC94acbb67b1C35D16C3297b", + "blockHash": "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + "blockNumber": 7951640, + "data": "0x", + "logIndex": 210, + "removed": false, + "topics": [ + "0x61014378f82a0d809aefaf87a8ac9505b89c321808287a6e7810f29304c1fce3", + "0x000000000000000000000000000000000000000000000000000000000000339f", + "0x418f32e5fb5113b1d9e8c3c38b08bd53cdc81e712b66dce1f9331294b4f0d3ee", + "0x04cc443be70eca5105f35ea6e832936c5882543c548d4163861b089e34e75a46" + ], + "transactionHash": "0x175be54f796aa29a44591aef4b5d4177e82ea2b7f66589ff852725d367e477c5", + "transactionIndex": 104, + "id": "log_1b0de9df" + } + ], + "logsBloom": "0x00000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000020000000000000000040010000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000100000000008000000000000000040000000000020000008000000000000000000000000000000001000002000100000000000000000000000000000000000020000000001000000000004000000000000000000000000000000800800000000000800000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x0c93ebaadbdd954bc88ef74a3c4d4c0a85e92e78", + "transactionHash": "0x175be54f796aa29a44591aef4b5d4177e82ea2b7f66589ff852725d367e477c5", + "transactionIndex": 104, + "type": "0x2" + + } + } + ], + transactionsRoot: "0x7edce7da7de1e0a10de9307100b4b39e1fe69f092117cdad9a213417f36608e1", + uncles: [] +}; + +export const emptyBlockData = { + baseFeePerGas: 60702551829, + difficulty: "0", + extraData: "0x", + gasLimit: 30000000, + gasUsed: 29855069, + hash: "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + logsBloom: "0x4675688d48cd6d2d31d8cc8fa15082811cf1e1e34801935688e51d855660efd5203c11a84bb08ae552307d59959409fa034c598650123c67c9dc8710023665106848e02bd4382a894e82ca2da818476e925dd669e0f6ebada81ca736ecc01ca22e048310d67eadda59e356c3d8418a540c4113c8c8e94da422b9815224f2a7ecf76a04b4c8b2c000aec9fd5d5440c7b874e32c256b3b81bd8614c8e48b6402d20f57b9b575213b98056579feee25352bd640f39f402280f04331507afe8792c13a52dc1651d029c875121a4adc07fe109b1625650ca6e8b116462d72e248e0a49a55b9db39521f521151b868aa23ab8f621d800b202a42516a40c028511e030e", + miner: "0xf36F155486299eCAff2D4F5160ed5114C1f66000", + mixHash: "0x2ebe643cccae521f1ef76cdcf0589d29cd6a926df466c3e9930a13c74c994f3b", + nonce: "0x0000000000000000", + number: 7951640, + parentHash: "0x7623f3258166598b7a085308557903b461996dd405f77c157572dfcbdbc8168d", + receiptsRoot: "0x629978d8b672729fe57f557c779488e8694cb65d04b50a5bb2be07fee3accff7", + sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + size: 81477, + stateRoot: "0xae398049f42398015accf8037e94a253094a3e72805dc5c33aa4158d9b69fd4f", + timestamp: 1668425976, + totalDifficulty: "10790000", + transactions: [ + ], + transactionsRoot: "0x7edce7da7de1e0a10de9307100b4b39e1fe69f092117cdad9a213417f36608e1", + uncles: [] +}; + +export const zkEvmBlockData = { + parentHash: "0x39a68345cff19c20bb8c5c0920dfbad119e2b63154d10cb1ea1c2c5c04b29c1b", + sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + miner: "0x22Ba753CA065d65D4d0b9f4FAC7a669746175199", + stateRoot: "0x24b8e3550568a91075a3afafec64b95e7d10ad64add7f2831761b54662925895", + transactionsRoot: "0xb1bbf5ca3b1d6de9d9938d37ece8596d4b88ed65a06523a4ef1c502ad53fe9b1", + receiptsRoot: "0x5e11666c15e878dd027140934798b5314dae024caf288af6d910528e96dab182", + logsBloom: "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000002000000000000000000000000000000000000000000000000000000000000800", + difficulty: "0", + totalDifficulty: "0", + size: 2030, + number: 13131, + gasLimit: 4000000, + gasUsed: 100158, + timestamp: 1668426037, + extraData: "0x", + mixHash: "0x0000000000000000000000000000000000000000000000000000000000000000", + nonce: "0x0000000000000000", + hash: "0x0a247c1f46e76f30a6781d120c3cd47905933dd23d6305ce661fcaf8c33f77d8", + transactions: [ + { + "hash": "0xeb0e24a9d5b32f9034756879f52abe9ebc6cd761ce67034d84cfb5a86f27a306", + "v": "0xb18", + "r": "0xcd5d7875aefbf8bf02c51531cf3dd081e3a8c430647b21813fa7af8b358509b1", + "s": "0x5fb6f8055946d42eb6bf5805e27e56fffaef748d356b91bf06633b0f3ca47977", + "from": "0xdef24a310c771C570F7511D9ce6fF431E8673E09", + "blockHash": "0x0a247c1f46e76f30a6781d120c3cd47905933dd23d6305ce661fcaf8c33f77d8", + "blockNumber": 13131, + "transactionIndex": 0, + "nonce": 1, + "gasPrice": "0", + "gas": 500000, + "to": "0x9D98DeAbC42dd696Deb9e40b4f1CAB7dDBF55988", + "value": "0", + "receipt": { + "root": "0x24b8e3550568a91075a3afafec64b95e7d10ad64add7f2831761b54662925895", + "cumulativeGasUsed": 100158, + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008000002000000000000000000000000000000000000000000000000000000000000800", + "logs": [ + { + "address": "0x9D98DeAbC42dd696Deb9e40b4f1CAB7dDBF55988", + "topics": [ + "0x25308c93ceeed162da955b3f7ce3e3f93606579e40fb92029faa9efe27545983" + ], + "data": "0x000000000000000000000000000000000000000000000000000000000000135f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000def24a310c771c570f7511d9ce6ff431e8673e0900000000000000000000000000000000000000000000000000b1a2bc2ec50000", + "blockNumber": 13131, + "transactionHash": "0xeb0e24a9d5b32f9034756879f52abe9ebc6cd761ce67034d84cfb5a86f27a306", + "transactionIndex": 0, + "blockHash": "0x0a247c1f46e76f30a6781d120c3cd47905933dd23d6305ce661fcaf8c33f77d8", + "logIndex": 0, + "removed": false, + "id": "log_28bd5432" + } + ], + "status": true, + "transactionHash": "0xeb0e24a9d5b32f9034756879f52abe9ebc6cd761ce67034d84cfb5a86f27a306", + "transactionIndex": 0, + "blockHash": "0x0a247c1f46e76f30a6781d120c3cd47905933dd23d6305ce661fcaf8c33f77d8", + "blockNumber": 13131, + "gasUsed": 100158, + "from": "0xdef24a310c771c570f7511d9ce6ff431e8673e09", + "to": "0x9d98deabc42dd696deb9e40b4f1cab7ddbf55988", + "contractAddress": null, + "type": "0x0" + } + } + ], + uncles: [] +}; diff --git a/tests/mock_data/connect_error.json b/tests/mock_data/connect_error.json new file mode 100644 index 0000000..148c091 --- /dev/null +++ b/tests/mock_data/connect_error.json @@ -0,0 +1,8 @@ +{ + "message": "Local: Broker transport failure", + "code": -195, + "errno": -195, + "origin": "kafka", + "isFatal": true, + "stack": "mock stack string" +} diff --git a/tests/mock_data/disconnected_error.json b/tests/mock_data/disconnected_error.json new file mode 100644 index 0000000..33d68f0 --- /dev/null +++ b/tests/mock_data/disconnected_error.json @@ -0,0 +1,8 @@ +{ + "message": "KafkaConsumer is disconnected", + "origin": "kafka", + "code": -172, + "errno": -172, + "isFatal": true, + "stack": "demo" +} diff --git a/tests/mock_data/ethereum_block.json b/tests/mock_data/ethereum_block.json new file mode 100644 index 0000000..ca53d84 --- /dev/null +++ b/tests/mock_data/ethereum_block.json @@ -0,0 +1,120 @@ +{ + "baseFeePerGas": 0, + "difficulty": "11732676900254043", + "extraData": "0x6575726f70652d77657374332d3131", + "gasLimit": 30000000, + "gasUsed": 18368256, + "hash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logsBloom": "0xe9bcd103470038b3d980004ac03114e90269ca09e87c03976a918c7a37e219182be4f865f4db018379616c4caa484b390e1c8109da9eb15128a40e309e7c2144f10307c09a11c3ca2a835dfa1b3329e4123a40b4a3e55bb1a66898a087b0066ab313a6a0061f4e8ba5848e6e56112d21495f5c4097100ffcce900170b5eab2c6c299991270b65c65007877924d09416c945107d7b752fd0c29884040ed1f063acaa8715b1149f4f2e6ef7bed81029b06463452ea608a20a29126089d64d8e071472dee9200300a74b1ffd683c8ae573845e8286485aeeb1a083e6f86121a7c706538a029e478127fa6c4339861f42b4ea26680e1611a2ac5a05a0a09456aa927", + "miner": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", + "mixHash": "0x04f9a68780f121f13465b40f9f2c6aa916d9b34ed5456c7dc8c8eb3783fe28f8", + "nonce": "0x187acde2984925d2", + "number": 15400000, + "parentHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "receiptsRoot": "0x74f2b011648081045832123ac9d8460e39e33b49409c8817ff9a465c5e1ce83f", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": 45916, + "stateRoot": "0x384b4d264ddaa491cc0068698a7808b09401a412dbdba28d4881504e59a1b3eb", + "timestamp": 1661304400, + "totalDifficulty": "57062913615916222641618", + "transactions": [ + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "from": "0xdDBC6E07a56d81D8028D850E5933f2F34e88a3b6", + "gas": 158645, + "gasPrice": "120000000000", + "hash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "input": "0x3912521500000000000000000000000039378cb121ca2217cd378c111c360d216188340100000000000000000000000000000000000000000000000001f0ce878b368c0000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000630eb8c4000000000000000000000000000000000000000000000000000000000000558f00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410f3ed172d63e158e1b02d28874cd68a2b35fbb3ed6b3a955ae3895b2be9afc5545d239102cc56a6acaad84d79d004b18ed4c2f0461eb74a5f7d93375f61647c71b00000000000000000000000000000000000000000000000000000000000000", + "nonce": 16315, + "to": "0x2094a142cE08a5054fc1CB0dDDd014DBac6D5ff2", + "transactionIndex": 0, + "value": "0", + "type": 0, + "chainId": "0x1", + "v": "0x1b", + "r": "0x2b7b850cf014e663b961f880dd4ebc5bf208a67af3675b01542deeed52aa35fe", + "s": "0x5b2ffb2f676b411a1142f9512105969b43c2c2e67709cc635d10b466666e7dbc" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "from": "0x26FD09c8B44AF53df38a9BAD41D5Abc55a1786AF", + "gas": 300015, + "gasPrice": "15429093101", + "maxPriorityFeePerGas": "7934355320", + "maxFeePerGas": "18190424064", + "hash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "input": "0xf5b22c2a000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b0000000000000000000000000000000000000000000000000830f9a504a4e2ec000000000000000000000000000000000000000003d562a7ca08eee000000000000000000000000000000000000000000000000003e49a2bca9a13800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf", + "nonce": 77316, + "to": "0x87d9dA48dB6e1F925CB67d3b7d2a292846c24cf7", + "transactionIndex": 1, + "value": "0", + "type": 2, + "chainId": "0x1", + "v": "0x0", + "r": "0xa5ef988cffa8df6b30dd95dbfc8f2cee02e50c1ca705298fda41f4db1655da85", + "s": "0xbb4184f6478e7ca6dcf607964ec4a58d221581e9d881d3a0ba2f61e11b99886" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "from": "0xD1b72A8Ae97f51D7bd4Af257A124175688924001", + "gas": 697060, + "gasPrice": "15429093100", + "maxPriorityFeePerGas": "7934355319", + "maxFeePerGas": "26010000000", + "hash": "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004", + "input": "0x6ac56d4ea520553f40b7937ba412d07007786429f3da4c37807487c1fc167b707921ad7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010059c08679fe2ae8b747fa322bfd84f377707c6d594bd3ca17ae171b6ddbf76657b8a1b0b704290ca51ef8035e0bce2440a38075d3e05cca17ae171b6ddbf7664659035db704290c8fdd5a1d42a9597489628900ae56a61edc128f00b868afb6dcca452fd611faa007ff8a1643760c9602ba8fe639cdbf27f9b10ffb78a7f2e0533d021f6dc5569902f3bf3ee3578b02d98512cbed63420d17afe3db4771ced465a78e57b958662b65045221341b2b0467d0f82376a558a886dcb3328b9a74b021629ef108ca290c8fdd5a1d4177e90440c0850ad0e05cca17ae171b6ddbf76646d336a0c4bce0fafd8c3f25a365bf33025e101686f68c9cb4d0d0120c24e732da", + "nonce": 7690, + "to": "0x767AF52d988D1241A346851a1B39cCd11357376E", + "transactionIndex": 2, + "value": "0", + "type": 2, + "chainId": "0x1", + "v": "0x0", + "r": "0xcd026b260087eb37007f8f65de384103037a749026c176067c6afe9c0c410d87", + "s": "0x1496a42f13e7824de865ada80f622d5a40481f7c4c5c163206c042a5465adf42" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "from": "0xFd25F5A3415e29f0AeeB5746E5D513DE67169225", + "gas": 90000, + "gasPrice": "15000000000", + "hash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "input": "0xa9059cbb000000000000000000000000e9d6c8d6667d2feb1b2c17f643b0c5b59bf196070000000000000000000000000000000000000000000000000000009c46a33800", + "nonce": 5788, + "to": "0x05237E2bd2dfAb39a135d254cABAE94b183C8baD", + "transactionIndex": 3, + "value": "0", + "type": 0, + "chainId": "0x1", + "v": "0x26", + "r": "0x53d25b40032ba48c352376553235638ccc239968fa9b573228e2c516de3bd07a", + "s": "0x7f937489eca893dbb932f85c694248a081accd862ab08cbaeef0dabc510bf806" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "from": "0xeF55CF262D752738CA47a07B5E5755053C45B336", + "gas": 222853, + "gasPrice": "15000000000", + "maxPriorityFeePerGas": "15000000000", + "maxFeePerGas": "15000000000", + "hash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "input": "0x7ff36ab5000000000000000000000000000000000000000000000000001db92bbd5df1c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b33600000000000000000000000000000000000000000000000000000000630585250000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000077cd71f1744036432cfd8d42e87cfe328832692a", + "nonce": 556, + "to": "0x25553828F22bDD19a20e4F12F052903Cb474a335", + "transactionIndex": 4, + "value": "150000000000000000", + "type": 2, + "chainId": "0x1", + "v": "0x0", + "r": "0x35a494d3f91a6e0628ba245321864d3dda16e94cc579f0590eb7957d4196bd38", + "s": "0x426bb580d008ae23910208add830ae2891411495234623f5ad08b42a26279061" + } + ], + "transactionsRoot": "0xb0a6c86e81f0bbff1261416384f103d4b4f314f6edf1c9b644423b0f8f373806", + "uncles": [] +} diff --git a/tests/mock_data/ethereum_full_block.json b/tests/mock_data/ethereum_full_block.json new file mode 100644 index 0000000..0bc2d40 --- /dev/null +++ b/tests/mock_data/ethereum_full_block.json @@ -0,0 +1,669 @@ +{ + "baseFeePerGas": "0x809aa8", + "difficulty": "0x809aa8", + "extraData": "0x6575726f70652d77657374332d3131", + "gasLimit": { + "high": 0, + "low": 0, + "unsigned": true + }, + "gasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "hash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logsBloom": "0xe9bcd103470038b3d980004ac03114e90269ca09e87c03976a918c7a37e219182be4f865f4db018379616c4caa484b390e1c8109da9eb15128a40e309e7c2144f10307c09a11c3ca2a835dfa1b3329e4123a40b4a3e55bb1a66898a087b0066ab313a6a0061f4e8ba5848e6e56112d21495f5c4097100ffcce900170b5eab2c6c299991270b65c65007877924d09416c945107d7b752fd0c29884040ed1f063acaa8715b1149f4f2e6ef7bed81029b06463452ea608a20a29126089d64d8e071472dee9200300a74b1ffd683c8ae573845e8286485aeeb1a083e6f86121a7c706538a029e478127fa6c4339861f42b4ea26680e1611a2ac5a05a0a09456aa927", + "miner": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", + "mixHash": "0x04f9a68780f121f13465b40f9f2c6aa916d9b34ed5456c7dc8c8eb3783fe28f8", + "nonce": { + "high": 0, + "low": 0, + "unsigned": true + }, + "number": { + "high": 0, + "low": 0, + "unsigned": true + }, + "parentHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "receiptsRoot": "0x74f2b011648081045832123ac9d8460e39e33b49409c8817ff9a465c5e1ce83f", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x809aa8", + "stateRoot": "0x384b4d264ddaa491cc0068698a7808b09401a412dbdba28d4881504e59a1b3eb", + "timestamp": { + "low": 0, + "high": 0, + "unsigned": true + }, + "totalDifficulty": "0x809aa8", + "transactions": [ + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "from": "0xdDBC6E07a56d81D8028D850E5933f2F34e88a3b6", + "gas": { + "high": 0, + "low": 0, + "unsigned": true + }, + "gasPrice": "0x809aa8", + "hash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "input": "0x3912521500000000000000000000000039378cb121ca2217cd378c111c360d216188340100000000000000000000000000000000000000000000000001f0ce878b368c0000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000630eb8c4000000000000000000000000000000000000000000000000000000000000558f00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410f3ed172d63e158e1b02d28874cd68a2b35fbb3ed6b3a955ae3895b2be9afc5545d239102cc56a6acaad84d79d004b18ed4c2f0461eb74a5f7d93375f61647c71b00000000000000000000000000000000000000000000000000000000000000", + "nonce": { + "high": 0, + "low": 0, + "unsigned": true + }, + "to": "0x2094a142cE08a5054fc1CB0dDDd014DBac6D5ff2", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "value": "0x809aa8", + "type": 0, + "chainId": "0x1", + "v": "0x1b", + "r": "0x2b7b850cf014e663b961f880dd4ebc5bf208a67af3675b01542deeed52aa35fe", + "s": "0x5b2ffb2f676b411a1142f9512105969b43c2c2e67709cc635d10b466666e7dbc", + "receipt": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "contractAddress": null, + "cumulativeGasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "effectiveGasPrice": "0x809aa8", + "from": "0xddbc6e07a56d81d8028d850e5933f2f34e88a3b6", + "gasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "logs": [ + { + "address": "0x2094a142cE08a5054fc1CB0dDDd014DBac6D5ff2", + "topics": [ + "0x59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a806" + ], + "data": "0x000000000000000000000000ddbc6e07a56d81d8028d850e5933f2f34e88a3b6000000000000000000000000be34e9b0e566c1e474c045c51a31141d8cdd42e866a867ad7562c1c2acb24007898e03a7d4d884b1b6adc9b765f488b8c264f82400000000000000000000000039378cb121ca2217cd378c111c360d216188340100000000000000000000000000000000000000000000000001f0ce878b368c0000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "removed": false, + "id": "log_4d1ea012" + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000004000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x2094a142ce08a5054fc1cb0dddd014dbac6d5ff2", + "transactionHash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": "0x0" + } + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "from": "0x26FD09c8B44AF53df38a9BAD41D5Abc55a1786AF", + "gas": { + "high": 0, + "low": 0, + "unsigned": true + }, + "gasPrice": { + "high": 0, + "low": 0, + "unsigned": true + }, + "hash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "input": "0xf5b22c2a000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b0000000000000000000000000000000000000000000000000830f9a504a4e2ec000000000000000000000000000000000000000003d562a7ca08eee000000000000000000000000000000000000000000000000003e49a2bca9a13800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf", + "nonce": { + "high": 0, + "low": 0, + "unsigned": true + }, + "to": "0x87d9dA48dB6e1F925CB67d3b7d2a292846c24cf7", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "value": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": 2, + "chainId": "0x1", + "v": "0x0", + "r": "0xa5ef988cffa8df6b30dd95dbfc8f2cee02e50c1ca705298fda41f4db1655da85", + "s": "0xbb4184f6478e7ca6dcf607964ec4a58d221581e9d881d3a0ba2f61e11b99886", + "receipt": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "contractAddress": null, + "cumulativeGasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "effectiveGasPrice": "0x809aa8", + "from": "0x26fd09c8b44af53df38a9bad41d5abc55a1786af", + "gasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "logs": [ + { + "address": "0x7D29A64504629172a429e64183D6673b9dAcbFCe", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b", + "0x0000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf" + ], + "data": "0x00000000000000000000000000000000000000000000008b250cfe7c897da513", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 1, + "removed": false, + "id": "log_ae82f14f" + }, + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000087d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "0x000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b" + ], + "data": "0x0000000000000000000000000000000000000000000000000830f9a504a4e2ec", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 2, + "removed": false, + "id": "log_0077ab72" + }, + { + "address": "0xcbBc981bD5B358D09a9346726115D3Ac8822d00b", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x00000000000000000000000087d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "0x0000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffff74daf3018376825aed0000000000000000000000000000000000000000000000000830f9a504a4e2ec000000000000000000000000000000000000000003e463a2436d093e19a92447000000000000000000000000000000000000000000000089ce59ab7ed6ba8bf9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb8ef", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 3, + "removed": false, + "id": "log_57fd3968" + } + ], + "logsBloom": "0x00000000020000000000000000000008000000000000000000000000000000000000000000000000000000000000000002000000080021000000000000000100000000000000000800000008000000000000000020000000000000000000000a00020000000000000000000000000000000000000000000000000110000800000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000202000000000000000000000000000020000000000000000000000200000000000020000000000000000000000000000000000000000000000", + "status": true, + "to": "0x87d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": "0x2" + } + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "from": "0xD1b72A8Ae97f51D7bd4Af257A124175688924001", + "gas": { + "high": 0, + "low": 0, + "unsigned": true + }, + "gasPrice": { + "high": 0, + "low": 0, + "unsigned": true + }, + "hash": "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004", + "input": "0x6ac56d4ea520553f40b7937ba412d07007786429f3da4c37807487c1fc167b707921ad7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010059c08679fe2ae8b747fa322bfd84f377707c6d594bd3ca17ae171b6ddbf76657b8a1b0b704290ca51ef8035e0bce2440a38075d3e05cca17ae171b6ddbf7664659035db704290c8fdd5a1d42a9597489628900ae56a61edc128f00b868afb6dcca452fd611faa007ff8a1643760c9602ba8fe639cdbf27f9b10ffb78a7f2e0533d021f6dc5569902f3bf3ee3578b02d98512cbed63420d17afe3db4771ced465a78e57b958662b65045221341b2b0467d0f82376a558a886dcb3328b9a74b021629ef108ca290c8fdd5a1d4177e90440c0850ad0e05cca17ae171b6ddbf76646d336a0c4bce0fafd8c3f25a365bf33025e101686f68c9cb4d0d0120c24e732da", + "nonce": { + "high": 0, + "low": 0, + "unsigned": true + }, + "to": "0x767AF52d988D1241A346851a1B39cCd11357376E", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "value": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": 2, + "chainId": "0x1", + "v": "0x0", + "r": "0xcd026b260087eb37007f8f65de384103037a749026c176067c6afe9c0c410d87", + "s": "0x1496a42f13e7824de865ada80f622d5a40481f7c4c5c163206c042a5465adf42", + "receipt": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "contractAddress": null, + "cumulativeGasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "effectiveGasPrice": "0x809aa8", + "from": "0xd1b72a8ae97f51d7bd4af257a124175688924001", + "gasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": false, + "to": "0x767af52d988d1241a346851a1b39ccd11357376e", + "transactionHash": "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": "0x2" + } + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "from": "0xFd25F5A3415e29f0AeeB5746E5D513DE67169225", + "gas": { + "high": 0, + "low": 0, + "unsigned": true + }, + "gasPrice": { + "high": 0, + "low": 0, + "unsigned": true + }, + "hash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "input": "0xa9059cbb000000000000000000000000e9d6c8d6667d2feb1b2c17f643b0c5b59bf196070000000000000000000000000000000000000000000000000000009c46a33800", + "nonce": { + "high": 0, + "low": 0, + "unsigned": true + }, + "to": "0x05237E2bd2dfAb39a135d254cABAE94b183C8baD", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "value": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": 0, + "chainId": "0x1", + "v": "0x26", + "r": "0x53d25b40032ba48c352376553235638ccc239968fa9b573228e2c516de3bd07a", + "s": "0x7f937489eca893dbb932f85c694248a081accd862ab08cbaeef0dabc510bf806", + "receipt": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "contractAddress": null, + "cumulativeGasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "effectiveGasPrice": "0x809aa8", + "from": "0xfd25f5a3415e29f0aeeb5746e5d513de67169225", + "gasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "logs": [ + { + "address": "0x05237E2bd2dfAb39a135d254cABAE94b183C8baD", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000fd25f5a3415e29f0aeeb5746e5d513de67169225", + "0x000000000000000000000000e9d6c8d6667d2feb1b2c17f643b0c5b59bf19607" + ], + "data": "0x0000000000000000000000000000000000000000000000000000009c46a33800", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 4, + "removed": false, + "id": "log_0999eae3" + } + ], + "logsBloom": "0x00000000000000000000000000000000000080000000000000000000000000000000000004000000000000000000000100000000000000000000000000000000000000000000000000010008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000010000000000000000000000000000000004100000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x05237e2bd2dfab39a135d254cabae94b183c8bad", + "transactionHash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": "0x0" + } + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "from": "0xeF55CF262D752738CA47a07B5E5755053C45B336", + "gas": { + "high": 0, + "low": 0, + "unsigned": true + }, + "gasPrice": { + "high": 0, + "low": 0, + "unsigned": true + }, + "hash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "input": "0x7ff36ab5000000000000000000000000000000000000000000000000001db92bbd5df1c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b33600000000000000000000000000000000000000000000000000000000630585250000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000077cd71f1744036432cfd8d42e87cfe328832692a", + "nonce": { + "high": 0, + "low": 0, + "unsigned": true + }, + "to": "0x25553828F22bDD19a20e4F12F052903Cb474a335", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "value": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": 2, + "chainId": "0x1", + "v": "0x0", + "r": "0x35a494d3f91a6e0628ba245321864d3dda16e94cc579f0590eb7957d4196bd38", + "s": "0x426bb580d008ae23910208add830ae2891411495234623f5ad08b42a26279061", + "receipt": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "contractAddress": null, + "cumulativeGasUsed": { + "high": 0, + "low": 0, + "unsigned": true + }, + "effectiveGasPrice": "0x809aa8", + "from": "0xef55cf262d752738ca47a07b5e5755053c45b336", + "gasUsed": 163011, + "logs": [ + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335" + ], + "data": "0x000000000000000000000000000000000000000000000000020f93f695254000", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 5, + "removed": false, + "id": "log_355686cf" + }, + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146" + ], + "data": "0x000000000000000000000000000000000000000000000000020f93f695254000", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 6, + "removed": false, + "id": "log_18a59fa1" + }, + { + "address": "0x77cd71f1744036432cFD8d42e87cfE328832692A", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146", + "0x00000000000000000000000077cd71f1744036432cfd8d42e87cfe328832692a" + ], + "data": "0x00000000000000000000000000000000000000000000000000019a99afe31b1d", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 7, + "removed": false, + "id": "log_b9c91be8" + }, + { + "address": "0x77cd71f1744036432cFD8d42e87cfE328832692A", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146", + "0x000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b336" + ], + "data": "0x000000000000000000000000000000000000000000000000001e79680ddb032a", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 8, + "removed": false, + "id": "log_ec799e93" + }, + { + "address": "0xDAD33eD1f355a73C867cD910Bc386093FF9Dc146", + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "data": "0x0000000000000000000000000000000000000000000000000acef4922019343f000000000000000000000000000000000000000000000000b34a309dfe4a1678", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 9, + "removed": false, + "id": "log_b520f7d0" + }, + { + "address": "0xDAD33eD1f355a73C867cD910Bc386093FF9Dc146", + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335", + "0x000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b336" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f93f69525400000000000000000000000000000000000000000000000000000201401bdbe1e470000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": { + "high": 0, + "low": 0, + "unsigned": true + }, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 10, + "removed": false, + "id": "log_98f28300" + } + ], + "logsBloom": "0x00200000000000000000000080000000000000000000000000000000000010000000000000000000080000000000000102000000080000000000000000000040000000000000400000000008000000200000001000000000000000008000000000000000000004020000000000010000000000000000000000000010000000000000000020000000000000000000000000000001800000080000004000000000000000000000000000002000000000000220000000000000000000000000000000000082000000000000000000000000000000000000001000000000000000000000200000000000000000000000000000000080000000400000000000000000", + "status": true, + "to": "0x25553828f22bdd19a20e4f12f052903cb474a335", + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": { + "high": 0, + "low": 0, + "unsigned": true + }, + "type": "0x2" + } + } + ], + "transactionsRoot": "0xb0a6c86e81f0bbff1261416384f103d4b4f314f6edf1c9b644423b0f8f373806", + "uncles": [] +} diff --git a/tests/mock_data/ethereum_transaction_receipts.json b/tests/mock_data/ethereum_transaction_receipts.json new file mode 100644 index 0000000..5689ca7 --- /dev/null +++ b/tests/mock_data/ethereum_transaction_receipts.json @@ -0,0 +1,257 @@ +{ + "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 87699, + "effectiveGasPrice": 120000000000, + "from": "0xddbc6e07a56d81d8028d850e5933f2f34e88a3b6", + "gasUsed": 87699, + "logs": [ + { + "address": "0x2094a142cE08a5054fc1CB0dDDd014DBac6D5ff2", + "topics": [ + "0x59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a806" + ], + "data": "0x000000000000000000000000ddbc6e07a56d81d8028d850e5933f2f34e88a3b6000000000000000000000000be34e9b0e566c1e474c045c51a31141d8cdd42e866a867ad7562c1c2acb24007898e03a7d4d884b1b6adc9b765f488b8c264f82400000000000000000000000039378cb121ca2217cd378c111c360d216188340100000000000000000000000000000000000000000000000001f0ce878b368c0000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": 15400000, + "transactionHash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "transactionIndex": 0, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 0, + "removed": false, + "id": "log_4d1ea012" + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000004000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x2094a142ce08a5054fc1cb0dddd014dbac6d5ff2", + "transactionHash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "transactionIndex": 0, + "type": "0x0" + }, + "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 218785, + "effectiveGasPrice": 15429093101, + "from": "0x26fd09c8b44af53df38a9bad41d5abc55a1786af", + "gasUsed": 131086, + "logs": [ + { + "address": "0x7D29A64504629172a429e64183D6673b9dAcbFCe", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b", + "0x0000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf" + ], + "data": "0x00000000000000000000000000000000000000000000008b250cfe7c897da513", + "blockNumber": 15400000, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 1, + "removed": false, + "id": "log_ae82f14f" + }, + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000087d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "0x000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b" + ], + "data": "0x0000000000000000000000000000000000000000000000000830f9a504a4e2ec", + "blockNumber": 15400000, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 2, + "removed": false, + "id": "log_0077ab72" + }, + { + "address": "0xcbBc981bD5B358D09a9346726115D3Ac8822d00b", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x00000000000000000000000087d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "0x0000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffff74daf3018376825aed0000000000000000000000000000000000000000000000000830f9a504a4e2ec000000000000000000000000000000000000000003e463a2436d093e19a92447000000000000000000000000000000000000000000000089ce59ab7ed6ba8bf9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb8ef", + "blockNumber": 15400000, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 3, + "removed": false, + "id": "log_57fd3968" + } + ], + "logsBloom": "0x00000000020000000000000000000008000000000000000000000000000000000000000000000000000000000000000002000000080021000000000000000100000000000000000800000008000000000000000020000000000000000000000a00020000000000000000000000000000000000000000000000000110000800000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000202000000000000000000000000000020000000000000000000000200000000000020000000000000000000000000000000000000000000000", + "status": true, + "to": "0x87d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "type": "0x2" + }, + "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 259525, + "effectiveGasPrice": 15429093100, + "from": "0xd1b72a8ae97f51d7bd4af257a124175688924001", + "gasUsed": 40740, + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": false, + "to": "0x767af52d988d1241a346851a1b39ccd11357376e", + "transactionHash": "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004", + "transactionIndex": 2, + "type": "0x2" + }, + "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 313533, + "effectiveGasPrice": 15000000000, + "from": "0xfd25f5a3415e29f0aeeb5746e5d513de67169225", + "gasUsed": 54008, + "logs": [ + { + "address": "0x05237E2bd2dfAb39a135d254cABAE94b183C8baD", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000fd25f5a3415e29f0aeeb5746e5d513de67169225", + "0x000000000000000000000000e9d6c8d6667d2feb1b2c17f643b0c5b59bf19607" + ], + "data": "0x0000000000000000000000000000000000000000000000000000009c46a33800", + "blockNumber": 15400000, + "transactionHash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "transactionIndex": 3, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 4, + "removed": false, + "id": "log_0999eae3" + } + ], + "logsBloom": "0x00000000000000000000000000000000000080000000000000000000000000000000000004000000000000000000000100000000000000000000000000000000000000000000000000010008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000010000000000000000000000000000000004100000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x05237e2bd2dfab39a135d254cabae94b183c8bad", + "transactionHash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "transactionIndex": 3, + "type": "0x0" + }, + "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9": { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 476544, + "effectiveGasPrice": 15000000000, + "from": "0xef55cf262d752738ca47a07b5e5755053c45b336", + "gasUsed": 163011, + "logs": [ + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335" + ], + "data": "0x000000000000000000000000000000000000000000000000020f93f695254000", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 5, + "removed": false, + "id": "log_355686cf" + }, + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146" + ], + "data": "0x000000000000000000000000000000000000000000000000020f93f695254000", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 6, + "removed": false, + "id": "log_18a59fa1" + }, + { + "address": "0x77cd71f1744036432cFD8d42e87cfE328832692A", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146", + "0x00000000000000000000000077cd71f1744036432cfd8d42e87cfe328832692a" + ], + "data": "0x00000000000000000000000000000000000000000000000000019a99afe31b1d", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 7, + "removed": false, + "id": "log_b9c91be8" + }, + { + "address": "0x77cd71f1744036432cFD8d42e87cfE328832692A", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146", + "0x000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b336" + ], + "data": "0x000000000000000000000000000000000000000000000000001e79680ddb032a", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 8, + "removed": false, + "id": "log_ec799e93" + }, + { + "address": "0xDAD33eD1f355a73C867cD910Bc386093FF9Dc146", + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "data": "0x0000000000000000000000000000000000000000000000000acef4922019343f000000000000000000000000000000000000000000000000b34a309dfe4a1678", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 9, + "removed": false, + "id": "log_b520f7d0" + }, + { + "address": "0xDAD33eD1f355a73C867cD910Bc386093FF9Dc146", + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335", + "0x000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b336" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f93f69525400000000000000000000000000000000000000000000000000000201401bdbe1e470000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 10, + "removed": false, + "id": "log_98f28300" + } + ], + "logsBloom": "0x00200000000000000000000080000000000000000000000000000000000010000000000000000000080000000000000102000000080000000000000000000040000000000000400000000008000000200000001000000000000000008000000000000000000004020000000000010000000000000000000000000010000000000000000020000000000000000000000000000001800000080000004000000000000000000000000000002000000000000220000000000000000000000000000000000082000000000000000000000000000000000000001000000000000000000000200000000000000000000000000000000080000000400000000000000000", + "status": true, + "to": "0x25553828f22bdd19a20e4f12f052903cb474a335", + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "type": "0x2" + } +} diff --git a/tests/mock_data/ethereum_transaction_receipts_array.json b/tests/mock_data/ethereum_transaction_receipts_array.json new file mode 100644 index 0000000..5d314d0 --- /dev/null +++ b/tests/mock_data/ethereum_transaction_receipts_array.json @@ -0,0 +1,257 @@ +[ + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 87699, + "effectiveGasPrice": 120000000000, + "from": "0xddbc6e07a56d81d8028d850e5933f2f34e88a3b6", + "gasUsed": 87699, + "logs": [ + { + "address": "0x2094a142cE08a5054fc1CB0dDDd014DBac6D5ff2", + "topics": [ + "0x59bed9ab5d78073465dd642a9e3e76dfdb7d53bcae9d09df7d0b8f5234d5a806" + ], + "data": "0x000000000000000000000000ddbc6e07a56d81d8028d850e5933f2f34e88a3b6000000000000000000000000be34e9b0e566c1e474c045c51a31141d8cdd42e866a867ad7562c1c2acb24007898e03a7d4d884b1b6adc9b765f488b8c264f82400000000000000000000000039378cb121ca2217cd378c111c360d216188340100000000000000000000000000000000000000000000000001f0ce878b368c0000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": 15400000, + "transactionHash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "transactionIndex": 0, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 0, + "removed": false, + "id": "log_4d1ea012" + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000004000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x2094a142ce08a5054fc1cb0dddd014dbac6d5ff2", + "transactionHash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "transactionIndex": 0, + "type": "0x0" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 218785, + "effectiveGasPrice": 15429093101, + "from": "0x26fd09c8b44af53df38a9bad41d5abc55a1786af", + "gasUsed": 131086, + "logs": [ + { + "address": "0x7D29A64504629172a429e64183D6673b9dAcbFCe", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b", + "0x0000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf" + ], + "data": "0x00000000000000000000000000000000000000000000008b250cfe7c897da513", + "blockNumber": 15400000, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 1, + "removed": false, + "id": "log_ae82f14f" + }, + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000087d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "0x000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b" + ], + "data": "0x0000000000000000000000000000000000000000000000000830f9a504a4e2ec", + "blockNumber": 15400000, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 2, + "removed": false, + "id": "log_0077ab72" + }, + { + "address": "0xcbBc981bD5B358D09a9346726115D3Ac8822d00b", + "topics": [ + "0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67", + "0x00000000000000000000000087d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "0x0000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffff74daf3018376825aed0000000000000000000000000000000000000000000000000830f9a504a4e2ec000000000000000000000000000000000000000003e463a2436d093e19a92447000000000000000000000000000000000000000000000089ce59ab7ed6ba8bf9fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeb8ef", + "blockNumber": 15400000, + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 3, + "removed": false, + "id": "log_57fd3968" + } + ], + "logsBloom": "0x00000000020000000000000000000008000000000000000000000000000000000000000000000000000000000000000002000000080021000000000000000100000000000000000800000008000000000000000020000000000000000000000a00020000000000000000000000000000000000000000000000000110000800000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000202000000000000000000000000000020000000000000000000000200000000000020000000000000000000000000000000000000000000000", + "status": true, + "to": "0x87d9da48db6e1f925cb67d3b7d2a292846c24cf7", + "transactionHash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "transactionIndex": 1, + "type": "0x2" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 259525, + "effectiveGasPrice": 15429093100, + "from": "0xd1b72a8ae97f51d7bd4af257a124175688924001", + "gasUsed": 40740, + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "status": false, + "to": "0x767af52d988d1241a346851a1b39ccd11357376e", + "transactionHash": "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004", + "transactionIndex": 2, + "type": "0x2" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 313533, + "effectiveGasPrice": 15000000000, + "from": "0xfd25f5a3415e29f0aeeb5746e5d513de67169225", + "gasUsed": 54008, + "logs": [ + { + "address": "0x05237E2bd2dfAb39a135d254cABAE94b183C8baD", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000fd25f5a3415e29f0aeeb5746e5d513de67169225", + "0x000000000000000000000000e9d6c8d6667d2feb1b2c17f643b0c5b59bf19607" + ], + "data": "0x0000000000000000000000000000000000000000000000000000009c46a33800", + "blockNumber": 15400000, + "transactionHash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "transactionIndex": 3, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 4, + "removed": false, + "id": "log_0999eae3" + } + ], + "logsBloom": "0x00000000000000000000000000000000000080000000000000000000000000000000000004000000000000000000000100000000000000000000000000000000000000000000000000010008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000010000000000000000000000000000000004100000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x05237e2bd2dfab39a135d254cabae94b183c8bad", + "transactionHash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "transactionIndex": 3, + "type": "0x0" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": 15400000, + "contractAddress": null, + "cumulativeGasUsed": 476544, + "effectiveGasPrice": 15000000000, + "from": "0xef55cf262d752738ca47a07b5e5755053c45b336", + "gasUsed": 163011, + "logs": [ + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335" + ], + "data": "0x000000000000000000000000000000000000000000000000020f93f695254000", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 5, + "removed": false, + "id": "log_355686cf" + }, + { + "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146" + ], + "data": "0x000000000000000000000000000000000000000000000000020f93f695254000", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 6, + "removed": false, + "id": "log_18a59fa1" + }, + { + "address": "0x77cd71f1744036432cFD8d42e87cfE328832692A", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146", + "0x00000000000000000000000077cd71f1744036432cfd8d42e87cfe328832692a" + ], + "data": "0x00000000000000000000000000000000000000000000000000019a99afe31b1d", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 7, + "removed": false, + "id": "log_b9c91be8" + }, + { + "address": "0x77cd71f1744036432cFD8d42e87cfE328832692A", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000dad33ed1f355a73c867cd910bc386093ff9dc146", + "0x000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b336" + ], + "data": "0x000000000000000000000000000000000000000000000000001e79680ddb032a", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 8, + "removed": false, + "id": "log_ec799e93" + }, + { + "address": "0xDAD33eD1f355a73C867cD910Bc386093FF9Dc146", + "topics": [ + "0x1c411e9a96e071241c2f21f7726b17ae89e3cab4c78be50e062b03a9fffbbad1" + ], + "data": "0x0000000000000000000000000000000000000000000000000acef4922019343f000000000000000000000000000000000000000000000000b34a309dfe4a1678", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 9, + "removed": false, + "id": "log_b520f7d0" + }, + { + "address": "0xDAD33eD1f355a73C867cD910Bc386093FF9Dc146", + "topics": [ + "0xd78ad95fa46c994b6551d0da85fc275fe613ce37657fb8d5e3d130840159d822", + "0x00000000000000000000000025553828f22bdd19a20e4f12f052903cb474a335", + "0x000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b336" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020f93f69525400000000000000000000000000000000000000000000000000000201401bdbe1e470000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": 15400000, + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logIndex": 10, + "removed": false, + "id": "log_98f28300" + } + ], + "logsBloom": "0x00200000000000000000000080000000000000000000000000000000000010000000000000000000080000000000000102000000080000000000000000000040000000000000400000000008000000200000001000000000000000008000000000000000000004020000000000010000000000000000000000000010000000000000000020000000000000000000000000000001800000080000004000000000000000000000000000002000000000000220000000000000000000000000000000000082000000000000000000000000000000000000001000000000000000000000200000000000000000000000000000000080000000400000000000000000", + "status": true, + "to": "0x25553828f22bdd19a20e4f12f052903cb474a335", + "transactionHash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "transactionIndex": 4, + "type": "0x2" + } +] diff --git a/tests/mock_data/log.json b/tests/mock_data/log.json new file mode 100644 index 0000000..d77362b --- /dev/null +++ b/tests/mock_data/log.json @@ -0,0 +1,16 @@ +{ + "address": "0x68a0F33CcEB2F7d3635e04DcC5FcA2b176108a07", + "topics": [ + "0xc12d213b215ecee7106a8e55cd2ee2f1157e4d6d787ad8fe68b09469cc1fc577", + "0x000000000000000000000000f2017ed6f046d4cbb293db0b3aba9b8fe10ca6df", + "0x000000000000000000000000000000000000000000000000000000000000365b" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000005100000000000000000000000000000000000000000000032d26d12e980b60000000000000000000000000000094b62040d663fa870d399e2fd044d40fbc0b79ec", + "blockNumber": 0, + "transactionHash": "0x738826631c0e38ab6f08284c1a0c9e75c80de15d3c11239b12739cbee250bec8", + "transactionIndex": 96, + "blockHash": "0x439350975cd7921db29dddd8bf6d0983258b52afdb2feac779d49f32ba81ffa9", + "logIndex": 536, + "removed": false, + "id": "log_8d14e3ee" +} diff --git a/tests/mock_data/metadata_mock.json b/tests/mock_data/metadata_mock.json new file mode 100644 index 0000000..2796730 --- /dev/null +++ b/tests/mock_data/metadata_mock.json @@ -0,0 +1,28 @@ +{ + "orig_broker_id": 1, + "orig_broker_name": "localhost:9092/1", + "topics": [ + { + "name": "chainId-137", + "partitions": [ + { + "id": 0, + "leader": 1, + "replicas": [ + 1 + ], + "isrs": [ + 1 + ] + } + ] + } + ], + "brokers": [ + { + "id": 1, + "host": "localhost", + "port": 9092 + } + ] +} diff --git a/tests/mock_data/mock_message.json b/tests/mock_data/mock_message.json new file mode 100644 index 0000000..d88bd91 --- /dev/null +++ b/tests/mock_data/mock_message.json @@ -0,0 +1,5 @@ +{ + "key": 123, + "value": "demo", + "topic": "chainId-137" +} diff --git a/tests/mock_data/polygon_block.json b/tests/mock_data/polygon_block.json new file mode 100644 index 0000000..69fa3c7 --- /dev/null +++ b/tests/mock_data/polygon_block.json @@ -0,0 +1,421 @@ +{ + "difficulty": "19", + "extraData": "0xd783010a0183626f7288676f312e31352e35856c696e757800000000000000003d2eb47fea129f62b3255e622ca042bfccf18eb689e513b0d76ef6b241b9089354a9ffd7571bd9bc4872fe7bacf44712cff43dee7ad5ae72d55191f81bae9e2600", + "gasLimit": 20000000, + "gasUsed": 19998098, + "hash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logsBloom": "0x1332994a1f87554414a90511d1a5b0be5b88bb22c54fe4a12c010492a3c669c078eb422164e19bf69133313915e409036a8494894eaa9107a59e65a1472eabb435804308921450388378ba5a95a628a098680420004e6f94c2390d368569c72db1345424c6119a1a8c75219090932cd95562995bd4bce43f9211d7b5956b7ce160956f10117a6518649c157350e15e0040733cd124b0685c8a597ffe82281ad22a91e46711e651fb81a9448ff4380588d45c0a10c0e0d0db558ca1ac1c604565f350df4642566666ca83022f82f3a90dfe08323015c0b6be3075e502501060a6ce5307e55c16b356add7266965e84a45fb84a004590be65a00a101a3ad511a8b", + "miner": "0x0000000000000000000000000000000000000000", + "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x0000000000000000", + "number": 15499996, + "parentHash": "0x83dd4c645a23375d29a841815d415509876f6929d0eb69d268b2c4bb19702cae", + "receiptsRoot": "0xbd60c1f934169726503e48bbf648b08ea609fff42c2e165b57913ff81177443e", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": 107232, + "stateRoot": "0x441e4a0eeec6fb14f836a1b28037ee7db156aa615522954352bc944dc5f711bc", + "timestamp": 1623205041, + "totalDifficulty": "158621621", + "transactions": [ + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "from": "0x32289746343FEeC10BAf56D5310A2605C65ee1D7", + "gas": { + "low": 414405, + "high": 0, + "unsigned": true + }, + "gasPrice": { + "low": 1215752192, + "high": 23, + "unsigned": true + }, + "hash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "input": "0xb81922050000000000000000000000000000000000000000000005ede20f01a459800000000000000000000000000000000000000000000000000033beeb2b88eb5e50220000000000000000000000000000000000000000000000000000000554a88272", + "nonce": 1815, + "to": "0xD078B62f8D9f5F69a6e6343e3e1eC9059770B830", + "transactionIndex": 0, + "value": { + "low": 0, + "high": 0, + "unsigned": true + }, + "type": 0, + "v": "0x136", + "r": "0x63b2cd0518cadc5c69d190c0dda4b529c429fc70194835a25cac51b125fffcce", + "s": "0xfb3006a49949f999f6eafc154edc6914b87c80867057fcce99967f1f3a38c92" + }, + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "from": "0x3976d02420e093607D71e2cfB0D31778176388B9", + "gas": { + "low": 180120, + "high": 0, + "unsigned": true + }, + "gasPrice": { + "low": 1820130816, + "high": 4, + "unsigned": true + }, + "hash": "0xc39417dddc4c1cd9a4544955e3433ddf1ed317f32cc22acb549e6936d5226188", + "input": "0xe2bbb158000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000174876e800", + "nonce": 1035, + "to": "0xe0e400617A20ADee7B2034324C3fa4C37bce97E8", + "transactionIndex": 1, + "value": { + "low": 0, + "high": 0, + "unsigned": true + }, + "type": 0, + "v": "0x135", + "r": "0x9540bd4a1415c861ced0f2ac3e2e751e09b0836c08f0eac522a4e17e86dc1b5a", + "s": "0x254621aafa842502d5d603cadd34b0a22d0a752f89c6bcbcee98338337cbc3d7" + }, + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "from": "0xd99B4fd532731d0797b872B8663D8B0b6CEb7954", + "gas": { + "low": 560000, + "high": 0, + "unsigned": true + }, + "gasPrice": { + "low": 1430065408, + "high": 2, + "unsigned": true + }, + "hash": "0xf98656f692e75752b65080dee8e968a8b1bd4e132fd46c8b8ded4d4f9feab259", + "input": "0x80caa605000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa84174000000000000000000000000a5e0829caced8ffdd4de3c43696c57f7d7a678ff0000000000000000000000001b02da8cb0d097eb8d57a175b88c7d8b4799750600000000000000000000000000000000000000000000000000000000000026a600000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000002791bca1f2de4661ed88a30c99a7a9449aa841740000000000000000000000001b02da8cb0d097eb8d57a175b88c7d8b47997506000000000000000000000000a5e0829caced8ffdd4de3c43696c57f7d7a678ff00000000000000000000000000000000000000000000000000000000000026a6", + "nonce": 0, + "to": "0x896F92e3f463F0618f23e5628aE74Fa2Fc45C93A", + "transactionIndex": 2, + "value": { + "low": 0, + "high": 0, + "unsigned": true + }, + "type": 0, + "v": "0x136", + "r": "0x9376cc6d776419bd13d8f52a209a22288517cbfedf51beb4b89e3721cba912b2", + "s": "0x2cb29e1aac13252b0ba9ac53fedc8182c3ab598985b48697e7dd81e3d9580968" + }, + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "from": "0xb162A57CE2D3e2f3DDcdc448768019c63E140669", + "gas": { + "low": 560000, + "high": 0, + "unsigned": true + }, + "gasPrice": { + "low": 1430065408, + "high": 2, + "unsigned": true + }, + "hash": "0x5ec4d79c4553edd554250add8a51a196ce9c3c2a1408fc434501762dced622c9", + "input": "0x80caa605000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f619000000000000000000000000a5e0829caced8ffdd4de3c43696c57f7d7a678ff0000000000000000000000001b02da8cb0d097eb8d57a175b88c7d8b4799750600000000000000000000000000000000000000000000000000000000000026ac00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000d500b1d8e8ef31e21c99d1db9a6444d3adf12700000000000000000000000007ceb23fd6bc0add59e62ac25578270cff1b9f6190000000000000000000000001b02da8cb0d097eb8d57a175b88c7d8b47997506000000000000000000000000a5e0829caced8ffdd4de3c43696c57f7d7a678ff00000000000000000000000000000000000000000000000000000000000026ac", + "nonce": 0, + "to": "0x896F92e3f463F0618f23e5628aE74Fa2Fc45C93A", + "transactionIndex": 3, + "value": { + "low": 0, + "high": 0, + "unsigned": true + }, + "type": 0, + "v": "0x136", + "r": "0xef5b2577115bf1970d24555a6a4cb1dc8ca46e23208db4b02e2fef6acd9d9e73", + "s": "0x4fab0cd9f0713b8440c29a81dae03b9af059987c8b2e74c818c584c61d7cce4c" + } + ], + "transactionsRoot": "0x61662aeaf581c2cc2f64a73386f5f82d096424d5e2ca0b702cc661eb76f46584", + "uncles": [], + "transactionReceipts": [ + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "contractAddress": null, + "cumulativeGasUsed": 345130, + "effectiveGasPrice": 100000000000, + "from": "0x32289746343feec10baf56d5310a2605c65ee1d7", + "gasUsed": 345130, + "logs": [ + { + "address": "0xD86b5923F3AD7b585eD81B448170ae026c65ae9a", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000032289746343feec10baf56d5310a2605c65ee1d7", + "0x0000000000000000000000000000000000000000000000000000000000000000" + ], + "data": "0x0000000000000000000000000000000000000000000005ede20f01a459800000", + "blockNumber": 15499996, + "transactionHash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "transactionIndex": 0, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 0, + "removed": false, + "id": "log_61ab6ddd" + }, + { + "address": "0xD86b5923F3AD7b585eD81B448170ae026c65ae9a", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x00000000000000000000000032289746343feec10baf56d5310a2605c65ee1d7", + "0x000000000000000000000000d078b62f8d9f5f69a6e6343e3e1ec9059770b830" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffff8d98ffff120cf98ae955", + "blockNumber": 15499996, + "transactionHash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "transactionIndex": 0, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 1, + "removed": false, + "id": "log_ec7cb066" + }, + { + "address": "0xD86b5923F3AD7b585eD81B448170ae026c65ae9a", + "topics": [ + "0xb53a8a5aa66e96b4627a60632ff728cd6991e142988ea8f28215fae565fe8ad0", + "0x00000000000000000000000032289746343feec10baf56d5310a2605c65ee1d7", + "0x000000000000000000000000d078b62f8d9f5f69a6e6343e3e1ec9059770b830" + ], + "data": "0x0000000000000000000000000000000000000000000005ede20f01a459800000", + "blockNumber": 15499996, + "transactionHash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "transactionIndex": 0, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 2, + "removed": false, + "id": "log_a50c8204" + }, + { + "address": "0xaAa5B9e6c589642f98a1cDA99B9D024B8407285A", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x000000000000000000000000ec12b5d70a84895f819fe037dc4eabdbd24707f2" + ], + "data": "0x000000000000000000000000000000000000000000000033d9772f3698bad8c2", + "blockNumber": 15499996, + "transactionHash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "transactionIndex": 0, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 3, + "removed": false, + "id": "log_a587aa40" + }, + { + "address": "0xaAa5B9e6c589642f98a1cDA99B9D024B8407285A", + "topics": [ + "0xf4d2b66b63836b39ffec28f88533e0f50c9136ab7d8d9b9976f93d3880e80205", + "0x000000000000000000000000aaa5b9e6c589642f98a1cda99b9d024b8407285a", + "0x000000000000000000000000ec12b5d70a84895f819fe037dc4eabdbd24707f2" + ], + "data": "0x000000000000000000000000000000000000000000000033d9772f3698bad8c2", + "blockNumber": 15499996, + "transactionHash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "transactionIndex": 0, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 4, + "removed": false, + "id": "log_ac6977dd" + }, + { + "address": "0x0000000000000000000000000000000000001010", + "topics": [ + "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", + "0x0000000000000000000000000000000000000000000000000000000000001010", + "0x00000000000000000000000032289746343feec10baf56d5310a2605c65ee1d7", + "0x00000000000000000000000028c0d4328520ed7e8657de141eee74a954b07c1f" + ], + "data": "0x000000000000000000000000000000000000000000000000007a9d64012210000000000000000000000000000000000000000000000000000a2e3468cb4c7c000000000000000000000000000000000000000000000000077861743c8240d90400000000000000000000000000000000000000000000000009b39704ca2a6c0000000000000000000000000000000000000000000000000778dc11a08362e904", + "blockNumber": 15499996, + "transactionHash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "transactionIndex": 0, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 5, + "removed": false, + "id": "log_dcac101b" + } + ], + "logsBloom": "0x00000000000000000000000000000000020000000000000000000000000000000000000000400000000000000000000002008000000000000000000000220000000000080000000000001008000000800000000000000000000100000001000020000000020000000000000000000800040000000000000080000010010000000000000000000000000000000000000000001000000000000000000000000000228000000000000000000008000000000400000000204040010000000800004000000002000000000001000000000000000000000000000010100000000020000010010000100000800000200000000000800000000000000000000000100080", + "status": true, + "to": "0xd078b62f8d9f5f69a6e6343e3e1ec9059770b830", + "transactionHash": "0x231642c27f10160670fa85140bbaba03646806b68168731aa8e4235c37121cc1", + "transactionIndex": 0, + "type": "0x0" + }, + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "contractAddress": null, + "cumulativeGasUsed": 444974, + "effectiveGasPrice": 19000000000, + "from": "0x3976d02420e093607d71e2cfb0d31778176388b9", + "gasUsed": 99844, + "logs": [ + { + "address": "0x0184316f58B9A44aCDD3e683257259dC0CF2202a", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x000000000000000000000000e0e400617a20adee7b2034324c3fa4c37bce97e8", + "0x0000000000000000000000003976d02420e093607d71e2cfb0d31778176388b9" + ], + "data": "0x0000000000000000000000000000000000000000000000000000000000000000", + "blockNumber": 15499996, + "transactionHash": "0xc39417dddc4c1cd9a4544955e3433ddf1ed317f32cc22acb549e6936d5226188", + "transactionIndex": 1, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 6, + "removed": false, + "id": "log_a0d5295e" + }, + { + "address": "0x0184316f58B9A44aCDD3e683257259dC0CF2202a", + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x0000000000000000000000003976d02420e093607d71e2cfb0d31778176388b9", + "0x000000000000000000000000e0e400617a20adee7b2034324c3fa4c37bce97e8" + ], + "data": "0x000000000000000000000000000000000000000000000000000000174876e800", + "blockNumber": 15499996, + "transactionHash": "0xc39417dddc4c1cd9a4544955e3433ddf1ed317f32cc22acb549e6936d5226188", + "transactionIndex": 1, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 7, + "removed": false, + "id": "log_998e0ce8" + }, + { + "address": "0x0184316f58B9A44aCDD3e683257259dC0CF2202a", + "topics": [ + "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925", + "0x0000000000000000000000003976d02420e093607d71e2cfb0d31778176388b9", + "0x000000000000000000000000e0e400617a20adee7b2034324c3fa4c37bce97e8" + ], + "data": "0xffffffffffffffffffffffffffffffffffffffffffffffffef0ae179d18a396e", + "blockNumber": 15499996, + "transactionHash": "0xc39417dddc4c1cd9a4544955e3433ddf1ed317f32cc22acb549e6936d5226188", + "transactionIndex": 1, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 8, + "removed": false, + "id": "log_e78d043c" + }, + { + "address": "0xe0e400617A20ADee7B2034324C3fa4C37bce97E8", + "topics": [ + "0x90890809c654f11d6e72a28fa60149770a0d11ec6c92319d6ceb2bb0a4ea1a15", + "0x0000000000000000000000003976d02420e093607d71e2cfb0d31778176388b9", + "0x000000000000000000000000000000000000000000000000000000000000000c" + ], + "data": "0x000000000000000000000000000000000000000000000000000000174876e800", + "blockNumber": 15499996, + "transactionHash": "0xc39417dddc4c1cd9a4544955e3433ddf1ed317f32cc22acb549e6936d5226188", + "transactionIndex": 1, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 9, + "removed": false, + "id": "log_0da9d61c" + }, + { + "address": "0x0000000000000000000000000000000000001010", + "topics": [ + "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", + "0x0000000000000000000000000000000000000000000000000000000000001010", + "0x0000000000000000000000003976d02420e093607d71e2cfb0d31778176388b9", + "0x00000000000000000000000028c0d4328520ed7e8657de141eee74a954b07c1f" + ], + "data": "0x0000000000000000000000000000000000000000000000000006bd581ce7f8000000000000000000000000000000000000000000000000061ea61a15066e6fbd00000000000000000000000000000000000000000000000778dc11a08362e9040000000000000000000000000000000000000000000000061e9f5cbce98677bd00000000000000000000000000000000000000000000000778e2cef8a04ae104", + "blockNumber": 15499996, + "transactionHash": "0xc39417dddc4c1cd9a4544955e3433ddf1ed317f32cc22acb549e6936d5226188", + "transactionIndex": 1, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 10, + "removed": false, + "id": "log_97df622b" + } + ], + "logsBloom": "0x00000000000000001000000000000000000002000400000000010000000000000000000000000200000000000000000008008000000000000000000000200000000000000000000000000008000000800000000000002000000100000000400000000000800000000000000000000000000008000010000080000010000000002000000000000000000000000000000000000000000000100000000000000000220000000000004000000000000000000000000000004000000000000000004000000002000000000001000000200000000010000000000000100000000000200010010000100000000000000000000000000000400000000000000000100000", + "status": true, + "to": "0xe0e400617a20adee7b2034324c3fa4c37bce97e8", + "transactionHash": "0xc39417dddc4c1cd9a4544955e3433ddf1ed317f32cc22acb549e6936d5226188", + "transactionIndex": 1, + "type": "0x0" + }, + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "contractAddress": null, + "cumulativeGasUsed": 569582, + "effectiveGasPrice": 10020000000, + "from": "0xd99b4fd532731d0797b872b8663d8b0b6ceb7954", + "gasUsed": 124608, + "logs": [ + { + "address": "0x0000000000000000000000000000000000001010", + "topics": [ + "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", + "0x0000000000000000000000000000000000000000000000000000000000001010", + "0x000000000000000000000000d99b4fd532731d0797b872b8663d8b0b6ceb7954", + "0x00000000000000000000000028c0d4328520ed7e8657de141eee74a954b07c1f" + ], + "data": "0x00000000000000000000000000000000000000000000000000046f91dc12c00000000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000778e2cef8a04ae1040000000000000000000000000000000000000000000000000373be1b0dc6400000000000000000000000000000000000000000000000000778e73e8a7c5da104", + "blockNumber": 15499996, + "transactionHash": "0xf98656f692e75752b65080dee8e968a8b1bd4e132fd46c8b8ded4d4f9feab259", + "transactionIndex": 2, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 11, + "removed": false, + "id": "log_869ffcba" + } + ], + "logsBloom": "0x00000000000000000000040000000000080000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000800000000000000000000100000000000000000000000000000000000000020000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000004000000000000000004000000000000000000001000000000000000000000000000000100000000000000000010000100000000000000000000000000000000000000000000000100000", + "status": true, + "to": "0x896f92e3f463f0618f23e5628ae74fa2fc45c93a", + "transactionHash": "0xf98656f692e75752b65080dee8e968a8b1bd4e132fd46c8b8ded4d4f9feab259", + "transactionIndex": 2, + "type": "0x0" + }, + { + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "blockNumber": 15499996, + "contractAddress": null, + "cumulativeGasUsed": 694146, + "effectiveGasPrice": 10020000000, + "from": "0xb162a57ce2d3e2f3ddcdc448768019c63e140669", + "gasUsed": 124564, + "logs": [ + { + "address": "0x0000000000000000000000000000000000001010", + "topics": [ + "0x4dfe1bbbcf077ddc3e01291eea2d5c70c2b422b415d95645b9adcfd678cb1d63", + "0x0000000000000000000000000000000000000000000000000000000000001010", + "0x000000000000000000000000b162a57ce2d3e2f3ddcdc448768019c63e140669", + "0x00000000000000000000000028c0d4328520ed7e8657de141eee74a954b07c1f" + ], + "data": "0x00000000000000000000000000000000000000000000000000046f2b3593d40000000000000000000000000000000000000000000000000003782dace9d9000000000000000000000000000000000000000000000000000778e73e8a7c5da1040000000000000000000000000000000000000000000000000373be81b4452c0000000000000000000000000000000000000000000000000778ebadb5b1f17504", + "blockNumber": 15499996, + "transactionHash": "0x5ec4d79c4553edd554250add8a51a196ce9c3c2a1408fc434501762dced622c9", + "transactionIndex": 3, + "blockHash": "0x805ba310d7aaf10499f3ec0a1264b72c07ae00b4078d55456773a9f77148a643", + "logIndex": 12, + "removed": false, + "id": "log_93c354b8" + } + ], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100008000000000000000000000000000000040000000000000000000000000800000000000000000000100000000800000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000004000000000000000004000000000000000000001000000000000000000000000000000100000000000000000010000100000000000000000000000000000000000000000000000100000", + "status": true, + "to": "0x896f92e3f463f0618f23e5628ae74fa2fc45c93a", + "transactionHash": "0x5ec4d79c4553edd554250add8a51a196ce9c3c2a1408fc434501762dced622c9", + "transactionIndex": 3, + "type": "0x0" + } + ] +} \ No newline at end of file diff --git a/tests/mock_data/raw_ethereum_block.json b/tests/mock_data/raw_ethereum_block.json new file mode 100644 index 0000000..2a211b1 --- /dev/null +++ b/tests/mock_data/raw_ethereum_block.json @@ -0,0 +1,122 @@ +{ + "baseFeePerGas": "0x9c7cf", + "difficulty": "0x0", + "extraData": "0x4e65746865726d696e64", + "gasLimit": "0x1c9c380", + "gasUsed": "0x1948ca2", + "hash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "logsBloom": "0xe9bcd103470038b3d980004ac03114e90269ca09e87c03976a918c7a37e219182be4f865f4db018379616c4caa484b390e1c8109da9eb15128a40e309e7c2144f10307c09a11c3ca2a835dfa1b3329e4123a40b4a3e55bb1a66898a087b0066ab313a6a0061f4e8ba5848e6e56112d21495f5c4097100ffcce900170b5eab2c6c299991270b65c65007877924d09416c945107d7b752fd0c29884040ed1f063acaa8715b1149f4f2e6ef7bed81029b06463452ea608a20a29126089d64d8e071472dee9200300a74b1ffd683c8ae573845e8286485aeeb1a083e6f86121a7c706538a029e478127fa6c4339861f42b4ea26680e1611a2ac5a05a0a09456aa927", + "miner": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", + "mixHash": "0x04f9a68780f121f13465b40f9f2c6aa916d9b34ed5456c7dc8c8eb3783fe28f8", + "nonce": "0x187acde2984925d2", + "number": "0x809aa8", + "parentHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "receiptsRoot": "0x74f2b011648081045832123ac9d8460e39e33b49409c8817ff9a465c5e1ce83f", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "size": "0x78abd", + "stateRoot": "0x384b4d264ddaa491cc0068698a7808b09401a412dbdba28d4881504e59a1b3eb", + "timestamp": "0x63dd4978", + "totalDifficulty": "0xa4a470", + "transactions": [ + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": "0x809aa8", + "from": "0xdDBC6E07a56d81D8028D850E5933f2F34e88a3b6", + "gas": "0x5208", + "gasPrice": "0x174876e800", + "hash": "0x5dadfe7b3b857ec95ce34d56037abbf16da4c1add8a89a1989eb939a7affb150", + "input": "0x3912521500000000000000000000000039378cb121ca2217cd378c111c360d216188340100000000000000000000000000000000000000000000000001f0ce878b368c0000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000630eb8c4000000000000000000000000000000000000000000000000000000000000558f00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410f3ed172d63e158e1b02d28874cd68a2b35fbb3ed6b3a955ae3895b2be9afc5545d239102cc56a6acaad84d79d004b18ed4c2f0461eb74a5f7d93375f61647c71b00000000000000000000000000000000000000000000000000000000000000", + "nonce": "0x1630c", + "to": "0x2094a142cE08a5054fc1CB0dDDd014DBac6D5ff2", + "transactionIndex": "0x0", + "value": "0xde0b6b3a7640000", + "type": "0x2", + "chainId": "0x0", + "v": "0x1b", + "r": "0x2b7b850cf014e663b961f880dd4ebc5bf208a67af3675b01542deeed52aa35fe", + "s": "0x5b2ffb2f676b411a1142f9512105969b43c2c2e67709cc635d10b466666e7dbc", + "maxFeePerGas": "0xee748684", + "maxPriorityFeePerGas": "0xee748684" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": "0x809aa8", + "from": "0x26FD09c8B44AF53df38a9BAD41D5Abc55a1786AF", + "gas": "0x5208", + "gasPrice": "0x174876e800", + "maxPriorityFeePerGas": "0xee748684", + "maxFeePerGas": "0xee748684", + "hash": "0x05dd0a3761721e857b2a6d743efe4813b87f394dc0a3ad0e12eaea2259771ff1", + "input": "0xf5b22c2a000000000000000000000000cbbc981bd5b358d09a9346726115d3ac8822d00b0000000000000000000000000000000000000000000000000830f9a504a4e2ec000000000000000000000000000000000000000003d562a7ca08eee000000000000000000000000000000000000000000000000003e49a2bca9a13800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e098207a163a0f8415d575cb5126ebf378f00bf", + "nonce": "0x1630c", + "to": "0x87d9dA48dB6e1F925CB67d3b7d2a292846c24cf7", + "transactionIndex": "0x1", + "value": "0", + "type": "0x2", + "chainId": "0x1", + "v": "0x0", + "r": "0xa5ef988cffa8df6b30dd95dbfc8f2cee02e50c1ca705298fda41f4db1655da85", + "s": "0xbb4184f6478e7ca6dcf607964ec4a58d221581e9d881d3a0ba2f61e11b99886" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": "0x809aa8", + "from": "0xD1b72A8Ae97f51D7bd4Af257A124175688924001", + "gas": "0x5208", + "gasPrice": "0x174876e800", + "maxPriorityFeePerGas": "0xee748684", + "maxFeePerGas": "0xee748684", + "hash": "0x63f9daa1f6e5c6684ccd8f21057a76d230329bfdf4a7106d11263c735aa2a004", + "input": "0x6ac56d4ea520553f40b7937ba412d07007786429f3da4c37807487c1fc167b707921ad7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000010059c08679fe2ae8b747fa322bfd84f377707c6d594bd3ca17ae171b6ddbf76657b8a1b0b704290ca51ef8035e0bce2440a38075d3e05cca17ae171b6ddbf7664659035db704290c8fdd5a1d42a9597489628900ae56a61edc128f00b868afb6dcca452fd611faa007ff8a1643760c9602ba8fe639cdbf27f9b10ffb78a7f2e0533d021f6dc5569902f3bf3ee3578b02d98512cbed63420d17afe3db4771ced465a78e57b958662b65045221341b2b0467d0f82376a558a886dcb3328b9a74b021629ef108ca290c8fdd5a1d4177e90440c0850ad0e05cca17ae171b6ddbf76646d336a0c4bce0fafd8c3f25a365bf33025e101686f68c9cb4d0d0120c24e732da", + "nonce": "0x1630c", + "to": "0x767AF52d988D1241A346851a1B39cCd11357376E", + "transactionIndex": "0x2", + "value": "0", + "type": "0x2", + "chainId": "0x1", + "v": "0x0", + "r": "0xcd026b260087eb37007f8f65de384103037a749026c176067c6afe9c0c410d87", + "s": "0x1496a42f13e7824de865ada80f622d5a40481f7c4c5c163206c042a5465adf42" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": "0x809aa8", + "from": "0xFd25F5A3415e29f0AeeB5746E5D513DE67169225", + "gas": "0x5208", + "gasPrice": "0x174876e800", + "hash": "0x9580999365c5c638615c13c22d91ffbead8f46464a0f6981dfd777c4d4b303c2", + "input": "0xa9059cbb000000000000000000000000e9d6c8d6667d2feb1b2c17f643b0c5b59bf196070000000000000000000000000000000000000000000000000000009c46a33800", + "nonce": 5788, + "to": "0x05237E2bd2dfAb39a135d254cABAE94b183C8baD", + "transactionIndex": "0x3", + "value": "0", + "type": "0x2", + "chainId": "0x1", + "v": "0x26", + "r": "0x53d25b40032ba48c352376553235638ccc239968fa9b573228e2c516de3bd07a", + "s": "0x7f937489eca893dbb932f85c694248a081accd862ab08cbaeef0dabc510bf806" + }, + { + "blockHash": "0x19823dbf42b70e95e552b48e3df646d2f41b510e20b8ee1878acb18eccbefb07", + "blockNumber": "0x809aa8", + "from": "0xeF55CF262D752738CA47a07B5E5755053C45B336", + "gas": "0x5208", + "gasPrice": "0xee748684", + "maxPriorityFeePerGas": "0xee748684", + "maxFeePerGas": "0xee748684", + "hash": "0x188048c014f1c59103c2d7d75151f3df8cc4d6146f0740bec650a48586e931e9", + "input": "0x7ff36ab5000000000000000000000000000000000000000000000000001db92bbd5df1c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000ef55cf262d752738ca47a07b5e5755053c45b33600000000000000000000000000000000000000000000000000000000630585250000000000000000000000000000000000000000000000000000000000000002000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000077cd71f1744036432cfd8d42e87cfe328832692a", + "nonce": "0x1630c", + "to": "0x25553828F22bDD19a20e4F12F052903Cb474a335", + "transactionIndex": "0x4", + "value": "150000000000000000", + "type": "0x2", + "chainId": "0x1", + "v": "0x0", + "r": "0x35a494d3f91a6e0628ba245321864d3dda16e94cc579f0590eb7957d4196bd38", + "s": "0x426bb580d008ae23910208add830ae2891411495234623f5ad08b42a26279061" + } + ], + "transactionsRoot": "0xb0a6c86e81f0bbff1261416384f103d4b4f314f6edf1c9b644423b0f8f373806", + "uncles": [] +} \ No newline at end of file diff --git a/tests/mock_data/zkevm_block.js b/tests/mock_data/zkevm_block.js new file mode 100644 index 0000000..4b7049e --- /dev/null +++ b/tests/mock_data/zkevm_block.js @@ -0,0 +1,221 @@ +export const blockData = { + baseFeePerGas: 60702551829, + difficulty: 0, + extraData: "0x", + gasLimit: 30000000, + gasUsed: 29855069, + hash: "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + logsBloom: "0x4675688d48cd6d2d31d8cc8fa15082811cf1e1e34801935688e51d855660efd5203c11a84bb08ae552307d59959409fa034c598650123c67c9dc8710023665106848e02bd4382a894e82ca2da818476e925dd669e0f6ebada81ca736ecc01ca22e048310d67eadda59e356c3d8418a540c4113c8c8e94da422b9815224f2a7ecf76a04b4c8b2c000aec9fd5d5440c7b874e32c256b3b81bd8614c8e48b6402d20f57b9b575213b98056579feee25352bd640f39f402280f04331507afe8792c13a52dc1651d029c875121a4adc07fe109b1625650ca6e8b116462d72e248e0a49a55b9db39521f521151b868aa23ab8f621d800b202a42516a40c028511e030e", + miner: "0xf36F155486299eCAff2D4F5160ed5114C1f66000", + mixHash: "0x2ebe643cccae521f1ef76cdcf0589d29cd6a926df466c3e9930a13c74c994f3b", + nonce: "0x0000000000000000", + number: 7951640, + parentHash: "0x7623f3258166598b7a085308557903b461996dd405f77c157572dfcbdbc8168d", + receiptsRoot: "0x629978d8b672729fe57f557c779488e8694cb65d04b50a5bb2be07fee3accff7", + sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + size: 81477, + stateRoot: "0xae398049f42398015accf8037e94a253094a3e72805dc5c33aa4158d9b69fd4f", + timestamp: 1668425976, + totalDifficulty: 10790000, + transactions: [ + { + "hash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b", + "nonce": 2, + "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46", + "blockNumber": 3, + "transactionIndex": 0, + "from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f", + "value": "123450000000000000", + "gas": 314159, + "gasPrice": "2000000000000", + "input": "0x57cb2fc4", + "receipt": { + "blockHash": "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + "blockNumber": 7951640, + "contractAddress": null, + "cumulativeGasUsed": 21510732, + "effectiveGasPrice": 62202551829, + "from": "0xdef24a310c771c570f7511d9ce6ff431e8673e09", + "gasUsed": 193518, + "logs": [ + { + "address": "0x0C93ebAadbDD954bC88EF74A3C4d4c0a85e92e78", + "blockHash": "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + "blockNumber": 7951640, + "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000def24a310c771c570f7511d9ce6ff431e8673e0900000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000135f0000000000000000000000000000000000000000000000000000000000000000", + "logIndex": 209, + "removed": false, + "topics": [ + "0x501781209a1f8899323b96b4ef08b168df93e0a90c673d1e4cce39366cb62f9b" + ], + "transactionHash": "0x175be54f796aa29a44591aef4b5d4177e82ea2b7f66589ff852725d367e477c5", + "transactionIndex": 104, + "id": "log_6444d866" + }, + { + "address": "0x762d09Ed110ace4EaC94acbb67b1C35D16C3297b", + "blockHash": "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + "blockNumber": 7951640, + "data": "0x", + "logIndex": 210, + "removed": false, + "topics": [ + "0xcb339b570a7f0b25afa7333371ff11192092a0aeace12b671f4c212f2815c6fe", + "0x000000000000000000000000000000000000000000000000000000000000339f", + "0x418f32e5fb5113b1d9e8c3c38b08bd53cdc81e712b66dce1f9331294b4f0d3ee", + "0x04cc443be70eca5105f35ea6e832936c5882543c548d4163861b089e34e75a46" + ], + "transactionHash": "0x175be54f796aa29a44591aef4b5d4177e82ea2b7f66589ff852725d367e477c5", + "transactionIndex": 104, + "id": "log_1b0de9df" + } + ], + "logsBloom": "0x00000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000200100000000000000000000000000020000000000000000040010000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000100000000008000000000000000040000000000020000008000000000000000000000000000000001000002000100000000000000000000000000000000000020000000001000000000004000000000000000000000000000000800800000000000800000000000000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x0c93ebaadbdd954bc88ef74a3c4d4c0a85e92e78", + "transactionHash": "0x175be54f796aa29a44591aef4b5d4177e82ea2b7f66589ff852725d367e477c5", + "transactionIndex": 104, + "type": "0x2" + + } + } + ], + transactionsRoot: "0x7edce7da7de1e0a10de9307100b4b39e1fe69f092117cdad9a213417f36608e1", + uncles: [] +}; + +export const emptyBlockData = { + baseFeePerGas: 60702551829, + difficulty: "0", + extraData: "0x", + gasLimit: 30000000, + gasUsed: 29855069, + hash: "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + logsBloom: "0x4675688d48cd6d2d31d8cc8fa15082811cf1e1e34801935688e51d855660efd5203c11a84bb08ae552307d59959409fa034c598650123c67c9dc8710023665106848e02bd4382a894e82ca2da818476e925dd669e0f6ebada81ca736ecc01ca22e048310d67eadda59e356c3d8418a540c4113c8c8e94da422b9815224f2a7ecf76a04b4c8b2c000aec9fd5d5440c7b874e32c256b3b81bd8614c8e48b6402d20f57b9b575213b98056579feee25352bd640f39f402280f04331507afe8792c13a52dc1651d029c875121a4adc07fe109b1625650ca6e8b116462d72e248e0a49a55b9db39521f521151b868aa23ab8f621d800b202a42516a40c028511e030e", + miner: "0xf36F155486299eCAff2D4F5160ed5114C1f66000", + mixHash: "0x2ebe643cccae521f1ef76cdcf0589d29cd6a926df466c3e9930a13c74c994f3b", + nonce: "0x0000000000000000", + number: 7951640, + parentHash: "0x7623f3258166598b7a085308557903b461996dd405f77c157572dfcbdbc8168d", + receiptsRoot: "0x629978d8b672729fe57f557c779488e8694cb65d04b50a5bb2be07fee3accff7", + sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + size: 81477, + stateRoot: "0xae398049f42398015accf8037e94a253094a3e72805dc5c33aa4158d9b69fd4f", + timestamp: 1668425976, + totalDifficulty: 10790000, + transactions: [ + ], + transactionsRoot: "0x7edce7da7de1e0a10de9307100b4b39e1fe69f092117cdad9a213417f36608e1", + uncles: [] +}; + +export const verifyBatchBlockData = { + baseFeePerGas: 60702551829, + difficulty: 0, + extraData: "0x", + gasLimit: 30000000, + gasUsed: 29855069, + hash: "0x77bfb3a31c534a336f09286011c02c6892ebdd761a0d3806d18570a32813ae01", + logsBloom: "0x4675688d48cd6d2d31d8cc8fa15082811cf1e1e34801935688e51d855660efd5203c11a84bb08ae552307d59959409fa034c598650123c67c9dc8710023665106848e02bd4382a894e82ca2da818476e925dd669e0f6ebada81ca736ecc01ca22e048310d67eadda59e356c3d8418a540c4113c8c8e94da422b9815224f2a7ecf76a04b4c8b2c000aec9fd5d5440c7b874e32c256b3b81bd8614c8e48b6402d20f57b9b575213b98056579feee25352bd640f39f402280f04331507afe8792c13a52dc1651d029c875121a4adc07fe109b1625650ca6e8b116462d72e248e0a49a55b9db39521f521151b868aa23ab8f621d800b202a42516a40c028511e030e", + miner: "0xf36F155486299eCAff2D4F5160ed5114C1f66000", + mixHash: "0x2ebe643cccae521f1ef76cdcf0589d29cd6a926df466c3e9930a13c74c994f3b", + nonce: "0x0000000000000000", + number: 8010587, + parentHash: "0x7623f3258166598b7a085308557903b461996dd405f77c157572dfcbdbc8168d", + receiptsRoot: "0x629978d8b672729fe57f557c779488e8694cb65d04b50a5bb2be07fee3accff7", + sha3Uncles: "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + size: 81477, + stateRoot: "0xae398049f42398015accf8037e94a253094a3e72805dc5c33aa4158d9b69fd4f", + timestamp: 1668425976, + "transactions": [ + { + "blockHash": "0x07f0fe1492ecfd3facf1a0216bfe59866a312222fcfcde8fa257761fd3ebcd4a", + "blockNumber": 8010587, + "chainId": "0x5", + "from": "0x22Ba753CA065d65D4d0b9f4FAC7a669746175199", + "gas": 324939, + "gasPrice": "25801939004", + "hash": "0x3f377eb02a5150d34c3446944f55236995a6018bacd674907df19d4be05f427f", + "input": "0x95297e24abab4f5d3a8680022221d255f0d6eab5f0aa15529410e92261f0a2010e208e82fa69e4a615f5a652e0594e118398095d8c73b59e266479a991e7c4eba34042610000000000000000000000000000000000000000000000000000000000002b3c2b9d9c53daf8b318a49dc72dc5aae9d57b1988b131b5a2675a20dd91e8d896671bba66cb3a73fbe9a9729be5b38717e0ceb82b0144df0d6ea0d01c6dee389944121df638b9c388de52312a693ad2c8b85ce261eaf858453379cea6a706cdc88e1ca30b95a69f97876e22939af2e0716d5943d1da16326374dbfc04aec0b2b1a503a580bbd43c5c4b640cc6737c223a17589dc00b8a99481d0ac977f2adb4d55a2474a105d7240c3bd5e0c2a2851475646fd80767587ec88089fe3d4fc9a8602c09cb8f889165438f3f898a9bbb61a78bd465ddecfb9f47305864d47bae4dc8ee1f0685f07859f3e484b4ece9ec9a8bc206edccd6b181465fe20e881329aa7a13", + "maxFeePerGas": "56794976267", + "maxPriorityFeePerGas": "124977559", + "nonce": 14545, + "r": "0xa967adc40a5fd66981c779bf3f1e4579f8b392592f61fcc61a2001195a9a8bcd", + "s": "0x7608dab2c8da9066e8bd95064553f8d63bde5f3968b2cba9a0e3bf75835db15e", + "to": "0x14cB06e8dE2222912138F9a062E5a4d9F4821409", + "transactionIndex": 90, + "type": 2, + "v": "0x0", + "value": "0", + "receipt": { + "blockHash": "0x07f0fe1492ecfd3facf1a0216bfe59866a312222fcfcde8fa257761fd3ebcd4a", + "blockNumber": 8010587, + "contractAddress": null, + "cumulativeGasUsed": 21731048, + "effectiveGasPrice": 25801939004, + "from": "0x22ba753ca065d65d4d0b9f4fac7a669746175199", + "gasUsed": 320426, + "logs": [ + { + "address": "0x762d09Ed110ace4EaC94acbb67b1C35D16C3297b", + "blockHash": "0x07f0fe1492ecfd3facf1a0216bfe59866a312222fcfcde8fa257761fd3ebcd4a", + "blockNumber": 8010587, + "data": "0x", + "logIndex": 340, + "removed": false, + "topics": [ + "0x61014378f82a0d809aefaf87a8ac9505b89c321808287a6e7810f29304c1fce3", + "0x0000000000000000000000000000000000000000000000000000000000004d8e", + "0x4d9ddd4b2000cc719861456680c31447b5cb40f54e9104bbaa16dade610f2c15", + "0xabab4f5d3a8680022221d255f0d6eab5f0aa15529410e92261f0a2010e208e82" + ], + "transactionHash": "0x3f377eb02a5150d34c3446944f55236995a6018bacd674907df19d4be05f427f", + "transactionIndex": 90, + "id": "log_e1b1e6e5" + }, + { + "address": "0x4701Aa9471d7bfAc765D87dcb1Ea6BB23AD32733", + "blockHash": "0x07f0fe1492ecfd3facf1a0216bfe59866a312222fcfcde8fa257761fd3ebcd4a", + "blockNumber": 8010587, + "data": "0x000000000000000000000000000000000000000000000000016345785d8a0000", + "logIndex": 341, + "removed": false, + "topics": [ + "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", + "0x00000000000000000000000014cb06e8de2222912138f9a062e5a4d9f4821409", + "0x00000000000000000000000022ba753ca065d65d4d0b9f4fac7a669746175199" + ], + "transactionHash": "0x3f377eb02a5150d34c3446944f55236995a6018bacd674907df19d4be05f427f", + "transactionIndex": 90, + "id": "log_5d2f2d8c" + }, + { + "address": "0x14cB06e8dE2222912138F9a062E5a4d9F4821409", + "blockHash": "0x07f0fe1492ecfd3facf1a0216bfe59866a312222fcfcde8fa257761fd3ebcd4a", + "blockNumber": 8010587, + "data": "0x", + "logIndex": 342, + "removed": false, + "topics": [ + "0x2cdf1508085a46c7241a7d78c5a1ec3d9246d1ab95e1c2a33676d29e17d42223", + "0x0000000000000000000000000000000000000000000000000000000000002b3c", + "0x00000000000000000000000022ba753ca065d65d4d0b9f4fac7a669746175199" + ], + "transactionHash": "0x3f377eb02a5150d34c3446944f55236995a6018bacd674907df19d4be05f427f", + "transactionIndex": 90, + "id": "log_c334f366" + } + ], + "logsBloom": "0x00000000000000001000000000000000000000000000000040000000000000000000000008000000000000000000000000000000000000000011000000040000010000000000020000000008000000044010000000000400000080000000000000000000002000000000000000000000000000000040000000000010040000000020000000000008000000000000000000000000000000000000000080000000000000000000208000000000000400000000000000000000000000000080000000000002000000000000004000040000000000000000008100002800000002000000000000000100000000000000000000000000000000000000000000000000", + "status": true, + "to": "0x14cb06e8de2222912138f9a062e5a4d9f4821409", + "transactionHash": "0x3f377eb02a5150d34c3446944f55236995a6018bacd674907df19d4be05f427f", + "transactionIndex": 90, + "type": "0x2" + }, + "transactionsRoot": "0x7edce7da7de1e0a10de9307100b4b39e1fe69f092117cdad9a213417f36608e1", + "uncles": [] + } + ] +}; diff --git a/tests/queue/queue.test.ts b/tests/queue/queue.test.ts new file mode 100644 index 0000000..6713d33 --- /dev/null +++ b/tests/queue/queue.test.ts @@ -0,0 +1,102 @@ +import { Queue } from "../../dist/internal/queue/queue"; + +describe("Common Queue class", () => { + const queue = new Queue(); + beforeEach(() => { + queue.clear(); + }); + + + describe("enqueue", () => { + test("Should add a single item to queue.", () => { + queue.enqueue("test"); + expect(queue.getLength()).toBe(1); + }); + + const cases = [ + "string", + 123, + new Promise((resolve) => setTimeout(resolve)), + { test: "test" } + ]; + test.each(cases)("The item added to the queue should be consistent with the one passed.", (a) => { + queue.enqueue(a); + expect(queue.front()).toBe(a); + }); + + test("Item should be added to the end of the queue", () => { + queue.enqueue("string1"); + queue.enqueue("string2"); + expect(queue.front()).toBe("string1"); + }); + }); + + describe("clear", () => { + test("Should empty the entire queue", () => { + queue.enqueue("test1"); + queue.enqueue("test2"); + queue.clear(); + expect(queue.getLength()).toBe(0); + }); + }); + + describe("shift", () => { + test("Should remove only the first item from queue.", () => { + queue.enqueue("test1"); + queue.enqueue("test2"); + queue.shift(); + expect(queue.getLength()).toBe(1); + expect(queue.front()).toBe("test2"); + }); + + test("Should remove only the first item from queue.", () => { + queue.enqueue("test1"); + queue.enqueue("test2"); + queue.shift(); + expect(queue.getLength()).toBe(1); + expect(queue.front()).toBe("test2"); + }); + + test("Should return the item being removed", () => { + queue.enqueue("test1"); + expect(queue.shift()).toBe("test1"); + }); + }); + + describe("front", () => { + test("Should return only the first item in the queue", () => { + queue.enqueue("test1"); + queue.enqueue("test2"); + expect(queue.front()).toBe("test1"); + }); + + test("Should not modify the queue length", () => { + queue.enqueue("test1"); + queue.enqueue("test2"); + queue.front(); + expect(queue.getLength()).toBe(2); + }); + }); + + describe("isEmpty", () => { + test("Should return true if the queue is empty and false if not.", () => { + queue.enqueue("test1"); + queue.enqueue("test2"); + expect(queue.isEmpty()).toBe(false); + queue.clear(); + expect(queue.isEmpty()).toBe(true); + }); + }); + + describe("getLength", () => { + test("Should return the correct length of the queue", () => { + queue.enqueue("test1"); + expect(queue.getLength()).toBe(1); + queue.enqueue("test2"); + expect(queue.getLength()).toBe(2); + queue.enqueue("test3"); + expect(queue.getLength()).toBe(3); + }); + }); + +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..392651e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "module": "NodeNext", + "allowSyntheticDefaultImports": true, + "moduleResolution": "nodenext", + "resolveJsonModule": true, + "esModuleInterop": true, + "target": "esnext", + "sourceMap": true, + "outDir": "dist/", + "declaration": true, + "strict": true, + "alwaysStrict": true, + "baseUrl": "./", + "paths": { + "@internal/*": [ + "internal/*" + ] + }, + }, + "include": [ + "./internal/**/*", + "./public/**/*" + ] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..c932a2d --- /dev/null +++ b/yarn.lock @@ -0,0 +1,6390 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@aws-crypto/crc32@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa" + integrity sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/ie11-detection@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz#640ae66b4ec3395cee6a8e94ebcd9f80c24cd688" + integrity sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q== + dependencies: + tslib "^1.11.1" + +"@aws-crypto/sha256-browser@3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz#05f160138ab893f1c6ba5be57cfd108f05827766" + integrity sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ== + dependencies: + "@aws-crypto/ie11-detection" "^3.0.0" + "@aws-crypto/sha256-js" "^3.0.0" + "@aws-crypto/supports-web-crypto" "^3.0.0" + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-locate-window" "^3.0.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-crypto/sha256-js@3.0.0", "@aws-crypto/sha256-js@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz#f06b84d550d25521e60d2a0e2a90139341e007c2" + integrity sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ== + dependencies: + "@aws-crypto/util" "^3.0.0" + "@aws-sdk/types" "^3.222.0" + tslib "^1.11.1" + +"@aws-crypto/supports-web-crypto@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz#5d1bf825afa8072af2717c3e455f35cda0103ec2" + integrity sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg== + dependencies: + tslib "^1.11.1" + +"@aws-crypto/util@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-3.0.0.tgz#1c7ca90c29293f0883468ad48117937f0fe5bfb0" + integrity sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w== + dependencies: + "@aws-sdk/types" "^3.222.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-sdk/client-cognito-identity@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.382.0.tgz#68a57892b283fb98c7c57f8ae924fa70190eb0d7" + integrity sha512-EgKpWh5w2uWNzjtcD3S3JLSuuwLvvaeaVih60xNEoyaxpqwgjAe0vw/8GT9q2nqhS0J+B3bQVYdkCyA5oQDVEQ== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/client-sts" "3.382.0" + "@aws-sdk/credential-provider-node" "3.382.0" + "@aws-sdk/middleware-host-header" "3.379.1" + "@aws-sdk/middleware-logger" "3.378.0" + "@aws-sdk/middleware-recursion-detection" "3.378.0" + "@aws-sdk/middleware-signing" "3.379.1" + "@aws-sdk/middleware-user-agent" "3.382.0" + "@aws-sdk/types" "3.378.0" + "@aws-sdk/util-endpoints" "3.382.0" + "@aws-sdk/util-user-agent-browser" "3.378.0" + "@aws-sdk/util-user-agent-node" "3.378.0" + "@smithy/config-resolver" "^2.0.1" + "@smithy/fetch-http-handler" "^2.0.1" + "@smithy/hash-node" "^2.0.1" + "@smithy/invalid-dependency" "^2.0.1" + "@smithy/middleware-content-length" "^2.0.1" + "@smithy/middleware-endpoint" "^2.0.1" + "@smithy/middleware-retry" "^2.0.1" + "@smithy/middleware-serde" "^2.0.1" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.1" + "@smithy/node-http-handler" "^2.0.1" + "@smithy/protocol-http" "^2.0.1" + "@smithy/smithy-client" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/url-parser" "^2.0.1" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.0.0" + "@smithy/util-defaults-mode-browser" "^2.0.1" + "@smithy/util-defaults-mode-node" "^2.0.1" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/client-sso-oidc@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.382.0.tgz#36bb5f828fb4ba85f0159e4d163ec2f608b77837" + integrity sha512-hTfvB1ftbrqaz7qiEkmRobzUQwG34oZlByobn8Frdr5ZQbJk969bX6evQAPyKlJEr26+kL9TnaX+rbLR/+gwHQ== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/middleware-host-header" "3.379.1" + "@aws-sdk/middleware-logger" "3.378.0" + "@aws-sdk/middleware-recursion-detection" "3.378.0" + "@aws-sdk/middleware-user-agent" "3.382.0" + "@aws-sdk/types" "3.378.0" + "@aws-sdk/util-endpoints" "3.382.0" + "@aws-sdk/util-user-agent-browser" "3.378.0" + "@aws-sdk/util-user-agent-node" "3.378.0" + "@smithy/config-resolver" "^2.0.1" + "@smithy/fetch-http-handler" "^2.0.1" + "@smithy/hash-node" "^2.0.1" + "@smithy/invalid-dependency" "^2.0.1" + "@smithy/middleware-content-length" "^2.0.1" + "@smithy/middleware-endpoint" "^2.0.1" + "@smithy/middleware-retry" "^2.0.1" + "@smithy/middleware-serde" "^2.0.1" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.1" + "@smithy/node-http-handler" "^2.0.1" + "@smithy/protocol-http" "^2.0.1" + "@smithy/smithy-client" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/url-parser" "^2.0.1" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.0.0" + "@smithy/util-defaults-mode-browser" "^2.0.1" + "@smithy/util-defaults-mode-node" "^2.0.1" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/client-sso@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.382.0.tgz#811e7cf2bb31b5b388794c17d407e1cdb2af7a7a" + integrity sha512-ge11t4hJllOF8pBNF0p1X52lLqUsLGAoey24fvk3fyvvczeLpegGYh2kdLG0iwFTDgRxaUqK+kboH5Wy9ux/pw== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/middleware-host-header" "3.379.1" + "@aws-sdk/middleware-logger" "3.378.0" + "@aws-sdk/middleware-recursion-detection" "3.378.0" + "@aws-sdk/middleware-user-agent" "3.382.0" + "@aws-sdk/types" "3.378.0" + "@aws-sdk/util-endpoints" "3.382.0" + "@aws-sdk/util-user-agent-browser" "3.378.0" + "@aws-sdk/util-user-agent-node" "3.378.0" + "@smithy/config-resolver" "^2.0.1" + "@smithy/fetch-http-handler" "^2.0.1" + "@smithy/hash-node" "^2.0.1" + "@smithy/invalid-dependency" "^2.0.1" + "@smithy/middleware-content-length" "^2.0.1" + "@smithy/middleware-endpoint" "^2.0.1" + "@smithy/middleware-retry" "^2.0.1" + "@smithy/middleware-serde" "^2.0.1" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.1" + "@smithy/node-http-handler" "^2.0.1" + "@smithy/protocol-http" "^2.0.1" + "@smithy/smithy-client" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/url-parser" "^2.0.1" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.0.0" + "@smithy/util-defaults-mode-browser" "^2.0.1" + "@smithy/util-defaults-mode-node" "^2.0.1" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/client-sts@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.382.0.tgz#176672b65e02b481d49bf13ab8cde3a95405f120" + integrity sha512-G5wgahrOqmrljjyLVGASIZUXIIdalbCo0z4PuFHdb2R2CVfwO8renfgrmk4brT9tIxIfen5bRA7ftXMe7yrgRA== + dependencies: + "@aws-crypto/sha256-browser" "3.0.0" + "@aws-crypto/sha256-js" "3.0.0" + "@aws-sdk/credential-provider-node" "3.382.0" + "@aws-sdk/middleware-host-header" "3.379.1" + "@aws-sdk/middleware-logger" "3.378.0" + "@aws-sdk/middleware-recursion-detection" "3.378.0" + "@aws-sdk/middleware-sdk-sts" "3.379.1" + "@aws-sdk/middleware-signing" "3.379.1" + "@aws-sdk/middleware-user-agent" "3.382.0" + "@aws-sdk/types" "3.378.0" + "@aws-sdk/util-endpoints" "3.382.0" + "@aws-sdk/util-user-agent-browser" "3.378.0" + "@aws-sdk/util-user-agent-node" "3.378.0" + "@smithy/config-resolver" "^2.0.1" + "@smithy/fetch-http-handler" "^2.0.1" + "@smithy/hash-node" "^2.0.1" + "@smithy/invalid-dependency" "^2.0.1" + "@smithy/middleware-content-length" "^2.0.1" + "@smithy/middleware-endpoint" "^2.0.1" + "@smithy/middleware-retry" "^2.0.1" + "@smithy/middleware-serde" "^2.0.1" + "@smithy/middleware-stack" "^2.0.0" + "@smithy/node-config-provider" "^2.0.1" + "@smithy/node-http-handler" "^2.0.1" + "@smithy/protocol-http" "^2.0.1" + "@smithy/smithy-client" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/url-parser" "^2.0.1" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-body-length-browser" "^2.0.0" + "@smithy/util-body-length-node" "^2.0.0" + "@smithy/util-defaults-mode-browser" "^2.0.1" + "@smithy/util-defaults-mode-node" "^2.0.1" + "@smithy/util-retry" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + fast-xml-parser "4.2.5" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-cognito-identity@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.382.0.tgz#1fa3555c288b36fc8bf6cb551d2499dd740f7298" + integrity sha512-fEsmPSylpQdALSS1pKMa9QghMk9xFiQCanmUWbQ7ETkcjuYuc/DK6GIA0pRjq/BROJJNSxKrSxt3TZPzVpvb3w== + dependencies: + "@aws-sdk/client-cognito-identity" "3.382.0" + "@aws-sdk/types" "3.378.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-env@3.378.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.378.0.tgz#a0f6291eff4e002c140599acede2433f58e4f4cb" + integrity sha512-B2OVdO9kBClDwGgWTBLAQwFV8qYTYGyVujg++1FZFSFMt8ORFdZ5fNpErvJtiSjYiOOQMzyBeSNhKyYNXCiJjQ== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-ini@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.382.0.tgz#a7ea55d4322c3d0f2d37b98c50ec866a162ecd19" + integrity sha512-31pi44WWri2WQmagqptUv7x3Nq8pQ6H06OCQx5goEm77SosSdwQwyBPrS9Pg0yI9aljFAxF+rZ75degsCorbQg== + dependencies: + "@aws-sdk/credential-provider-env" "3.378.0" + "@aws-sdk/credential-provider-process" "3.378.0" + "@aws-sdk/credential-provider-sso" "3.382.0" + "@aws-sdk/credential-provider-web-identity" "3.378.0" + "@aws-sdk/types" "3.378.0" + "@smithy/credential-provider-imds" "^2.0.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-node@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.382.0.tgz#67e661d090ecd85ae05af25e909c3d9f78f731bf" + integrity sha512-q6AWCCb0E0cH/Y5Dtln0QssbCBXDbV4PoTV3EdRuGoJcHyNfHJ8X0mqcc7k44wG4Piazu+ufZThvn43W7W9a4g== + dependencies: + "@aws-sdk/credential-provider-env" "3.378.0" + "@aws-sdk/credential-provider-ini" "3.382.0" + "@aws-sdk/credential-provider-process" "3.378.0" + "@aws-sdk/credential-provider-sso" "3.382.0" + "@aws-sdk/credential-provider-web-identity" "3.378.0" + "@aws-sdk/types" "3.378.0" + "@smithy/credential-provider-imds" "^2.0.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-process@3.378.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.378.0.tgz#8fd594c9600f9e4b7121f3cf2cea13b4d37f09e5" + integrity sha512-KFTIy7u+wXj3eDua4rgS0tODzMnXtXhAm1RxzCW9FL5JLBBrd82ymCj1Dp72217Sw5Do6NjCnDTTNkCHZMA77w== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-sso@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.382.0.tgz#a256215276f9b67afdeb36a4048f7484a46df824" + integrity sha512-tKCQKqxnAHeRD7pQNmDmLWwC7pt5koo6yiQTVQ382U+8xx7BNsApE1zdC4LrtrVN1FYqVbw5kXjYFtSCtaUxGA== + dependencies: + "@aws-sdk/client-sso" "3.382.0" + "@aws-sdk/token-providers" "3.382.0" + "@aws-sdk/types" "3.378.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/credential-provider-web-identity@3.378.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.378.0.tgz#019db9f17bd9fb2fd9a4171fe3b443c9e049a70a" + integrity sha512-GWjydOszhc4xDF8xuPtBvboglXQr0gwCW1oHAvmLcOT38+Hd6qnKywnMSeoXYRPgoKfF9TkWQgW1jxplzCG0UA== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/credential-providers@^3.186.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/credential-providers/-/credential-providers-3.382.0.tgz#adb47dbd6fb4371e92249a11e491f5a40ce4af92" + integrity sha512-+emgPCb8t5ODLpE1GeCkKaI6lx9M3RLQCYBGYkm/2o8FyvNeob9IBs6W8ufUTlnl4YRdKjDOlcfDtS00wCVHfA== + dependencies: + "@aws-sdk/client-cognito-identity" "3.382.0" + "@aws-sdk/client-sso" "3.382.0" + "@aws-sdk/client-sts" "3.382.0" + "@aws-sdk/credential-provider-cognito-identity" "3.382.0" + "@aws-sdk/credential-provider-env" "3.378.0" + "@aws-sdk/credential-provider-ini" "3.382.0" + "@aws-sdk/credential-provider-node" "3.382.0" + "@aws-sdk/credential-provider-process" "3.378.0" + "@aws-sdk/credential-provider-sso" "3.382.0" + "@aws-sdk/credential-provider-web-identity" "3.378.0" + "@aws-sdk/types" "3.378.0" + "@smithy/credential-provider-imds" "^2.0.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-host-header@3.379.1": + version "3.379.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.379.1.tgz#26d8af6100de4e03d201553360dfe16e10ae1aa5" + integrity sha512-LI4KpAFWNWVr2aH2vRVblr0Y8tvDz23lj8LOmbDmCrzd5M21nxuocI/8nEAQj55LiTIf9Zs+dHCdsyegnFXdrA== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/protocol-http" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-logger@3.378.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.378.0.tgz#f27fe3a979f3ef49034a860aa2c38c8a16faa879" + integrity sha512-l1DyaDLm3KeBMNMuANI3scWh8Xvu248x+vw6Z7ExWOhGXFmQ1MW7YvASg/SdxWkhlF9HmkkTif1LdMB22x6QDA== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-recursion-detection@3.378.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.378.0.tgz#706f505f608a766d617fbdad20ca30a7abccb311" + integrity sha512-mUMfHAz0oGNIWiTZHTVJb+I515Hqs2zx1j36Le4MMiiaMkPW1SRUF1FIwGuc1wh6E8jB5q+XfEMriDjRi4TZRA== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/protocol-http" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-sdk-sts@3.379.1": + version "3.379.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.379.1.tgz#4238aa2fa4ad4b0f7e0f6bb08d7c131b7d6a2baa" + integrity sha512-SK3gSyT0XbLiY12+AjLFYL9YngxOXHnZF3Z33Cdd4a+AUYrVBV7JBEEGD1Nlwrcmko+3XgaKlmgUaR5s91MYvg== + dependencies: + "@aws-sdk/middleware-signing" "3.379.1" + "@aws-sdk/types" "3.378.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/middleware-signing@3.379.1": + version "3.379.1" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.379.1.tgz#ebb7912868076babec851f9f703862dae6583a89" + integrity sha512-kBk2ZUvR84EM4fICjr8K+Ykpf8SI1UzzPp2/UVYZ0X+4H/ZCjfSqohGRwHykMqeplne9qHSL7/rGJs1H3l3gPg== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/protocol-http" "^2.0.1" + "@smithy/signature-v4" "^2.0.0" + "@smithy/types" "^2.0.2" + "@smithy/util-middleware" "^2.0.0" + tslib "^2.5.0" + +"@aws-sdk/middleware-user-agent@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.382.0.tgz#d30cf323e3dbc6e87909d382ec7c1245c7505016" + integrity sha512-LFRW1jmXOrOAd3911ktn6oaYmuurNnulbdRMOUdwz99GGdLVFipQhOi9idKswb8IOhPa4jEVQt25Kcv7ctvu0A== + dependencies: + "@aws-sdk/types" "3.378.0" + "@aws-sdk/util-endpoints" "3.382.0" + "@smithy/protocol-http" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/token-providers@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.382.0.tgz#3485341d2998e5dbf0d3e61d272f7a5f930a4193" + integrity sha512-axn4IyPpHdkXi8G06KCB3tPz79DipZFFH9N9YVDpLMnDYTdfX36HGdYzINaQc+z+XPbEpa1ZpoIzWScHRjFjdg== + dependencies: + "@aws-sdk/client-sso-oidc" "3.382.0" + "@aws-sdk/types" "3.378.0" + "@smithy/property-provider" "^2.0.0" + "@smithy/shared-ini-file-loader" "^2.0.0" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/types@3.378.0", "@aws-sdk/types@^3.222.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.378.0.tgz#93a811ccdf15c81b1947f1cd67922c4690792189" + integrity sha512-qP0CvR/ItgktmN8YXpGQglzzR/6s0nrsQ4zIfx3HMwpsBTwuouYahcCtF1Vr82P4NFcoDA412EJahJ2pIqEd+w== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/util-endpoints@3.382.0": + version "3.382.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.382.0.tgz#534c491624c9eac517148ab4f833b9b7332f16bb" + integrity sha512-flajPyjmjNG67fXk7l4GoTB/7J11VBqtFZXuuAZKhKU07Ia3IQupsFqNf5lV8D44ZgjnKH0fTGnv3dUALjW7Wg== + dependencies: + "@aws-sdk/types" "3.378.0" + tslib "^2.5.0" + +"@aws-sdk/util-locate-window@^3.0.0": + version "3.310.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz#b071baf050301adee89051032bd4139bba32cc40" + integrity sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w== + dependencies: + tslib "^2.5.0" + +"@aws-sdk/util-user-agent-browser@3.378.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.378.0.tgz#e756215da5bd1654a308b4e5383ebdcfc938fb0a" + integrity sha512-FSCpagzftK1W+m7Ar6lpX7/Gr9y5P56nhFYz8U4EYQ4PkufS6czWX9YW+/FA5OYV0vlQ/SvPqMnzoHIPUNhZrQ== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/types" "^2.0.2" + bowser "^2.11.0" + tslib "^2.5.0" + +"@aws-sdk/util-user-agent-node@3.378.0": + version "3.378.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.378.0.tgz#7af728f1823e860853998166a2bda0f0044251ef" + integrity sha512-IdwVJV0E96MkJeFte4dlWqvB+oiqCiZ5lOlheY3W9NynTuuX0GGYNC8Y9yIsV8Oava1+ujpJq0ww6qXdYxmO4A== + dependencies: + "@aws-sdk/types" "3.378.0" + "@smithy/node-config-provider" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.5.tgz#234d98e1551960604f1246e6475891a570ad5658" + integrity sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ== + dependencies: + "@babel/highlight" "^7.22.5" + +"@babel/compat-data@^7.22.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" + integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.9.tgz#bd96492c68822198f33e8a256061da3cf391f58f" + integrity sha512-G2EgeufBcYw27U4hhoIwFcgc1XU7TlXJ3mv04oOv1WCuo900U/anZSPzEqNjwdjgffkk2Gs0AN0dW1CKVLcG7w== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-module-transforms" "^7.22.9" + "@babel/helpers" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.8" + "@babel/types" "^7.22.5" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.2" + semver "^6.3.1" + +"@babel/generator@^7.22.7", "@babel/generator@^7.22.9", "@babel/generator@^7.7.2": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.9.tgz#572ecfa7a31002fa1de2a9d91621fd895da8493d" + integrity sha512-KtLMbmicyuK2Ak/FTCJVbDnkN1SlT8/kceFTiuDiiRUUSMnHMidxSCdG4ndkTOHHpoomWe/4xkvHkEOncwjYIw== + dependencies: + "@babel/types" "^7.22.5" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-annotate-as-pure@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz#e7f06737b197d580a01edf75d97e2c8be99d3882" + integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.5.tgz#a3f4758efdd0190d8927fcffd261755937c71878" + integrity sha512-m1EP3lVOPptR+2DwD125gziZNcmoNSHGmJROKoy87loWUQyJaVXDgpmruWqDARZSmtYQ+Dl25okU8+qhVzuykw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.9.tgz#f9d0a7aaaa7cd32a3f31c9316a69f5a9bcacb892" + integrity sha512-7qYrNM6HjpnPHJbopxmb8hSPoZ0gsX8IvUS32JGVoy+pU9e5N0nLr1VjJoR6kA4d9dmGLxNYOjeB8sUDal2WMw== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-validator-option" "^7.22.5" + browserslist "^4.21.9" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-create-class-features-plugin@^7.22.5", "@babel/helper-create-class-features-plugin@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.9.tgz#c36ea240bb3348f942f08b0fbe28d6d979fab236" + integrity sha512-Pwyi89uO4YrGKxL/eNJ8lfEH55DnRloGPOseaA8NFNL6jAUnn+KccaISiFazCj5IolPPDjGSdzQzXVzODVRqUQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + semver "^6.3.1" + +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz#9d8e61a8d9366fe66198f57c40565663de0825f6" + integrity sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + regexpu-core "^5.3.1" + semver "^6.3.1" + +"@babel/helper-define-polyfill-provider@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.2.tgz#82c825cadeeeee7aad237618ebbe8fa1710015d7" + integrity sha512-k0qnnOqHn5dK9pZpfD5XXZ9SojAITdCKRn2Lp6rnDGzIbaP0rHyMPk/4wsSxVBVz4RfN0q6VpXWP2pDGIoQ7hw== + dependencies: + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-plugin-utils" "^7.22.5" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + +"@babel/helper-environment-visitor@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" + integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== + +"@babel/helper-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz#ede300828905bb15e582c037162f99d5183af1be" + integrity sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ== + dependencies: + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-member-expression-to-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" + integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" + integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" + integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/helper-optimise-call-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz#f21531a9ccbff644fdd156b4077c16ff0c3f609e" + integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-remap-async-to-generator@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz#53a25b7484e722d7efb9c350c75c032d4628de82" + integrity sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-wrap-function" "^7.22.9" + +"@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" + integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz#007f15240b5751c537c40e77abb4e89eeaaa8847" + integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" + integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== + +"@babel/helper-validator-identifier@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" + integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== + +"@babel/helper-validator-option@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" + integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== + +"@babel/helper-wrap-function@^7.22.9": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.9.tgz#189937248c45b0182c1dcf32f3444ca153944cb9" + integrity sha512-sZ+QzfauuUEfxSEjKFmi3qDSHgLsTPK/pEpoD/qonZKOtTPTLbf59oabPQ4rKekt9lFcj/hTZaOhWwFYrgjk+Q== + dependencies: + "@babel/helper-function-name" "^7.22.5" + "@babel/template" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/helpers@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.6.tgz#8e61d3395a4f0c5a8060f309fb008200969b5ecd" + integrity sha512-YjDs6y/fVOYFV8hAf1rxd1QvR9wJe1pDBZ2AREKq/SDayfPzgk0PBnVuTCE5X1acEpMMNOVUqoe+OwiZGJ+OaA== + dependencies: + "@babel/template" "^7.22.5" + "@babel/traverse" "^7.22.6" + "@babel/types" "^7.22.5" + +"@babel/highlight@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.5.tgz#aa6c05c5407a67ebce408162b7ede789b4d22031" + integrity sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw== + dependencies: + "@babel/helper-validator-identifier" "^7.22.5" + chalk "^2.0.0" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.5", "@babel/parser@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.7.tgz#df8cf085ce92ddbdbf668a7f186ce848c9036cae" + integrity sha512-7NF8pOkHP5o2vpmGgNGcfAeCvOYhGLyA3Z4eBQkT1RJlWu47n63bCs93QfJ2hIAFCil7L5P2IWhs1oToVgrL0Q== + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e" + integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca" + integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.5" + +"@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": + version "7.21.0-placeholder-for-preset-env.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" + integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== + +"@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz#af613d2cd5e643643b65cded64207b15c85cb78e" + integrity sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + +"@babel/plugin-syntax-import-assertions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz#07d252e2aa0bc6125567f742cd58619cb14dce98" + integrity sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-attributes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.22.5.tgz#ab840248d834410b829f569f5262b9e517555ecb" + integrity sha512-KwvoWDeNKPETmozyFE0P2rOLqh39EoQHNjqizrI5B8Vt0ZNS7M56s7dAiAqbYfiAYOuIzIh96z3iR2ktgu3tEg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.22.5", "@babel/plugin-syntax-jsx@^7.7.2": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz#a6b68e84fb76e759fc3b93e901876ffabbe1d918" + integrity sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.22.5", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz#aac8d383b062c5072c647a31ef990c1d0af90272" + integrity sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" + +"@babel/plugin-transform-arrow-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz#e5ba566d0c58a5b2ba2a8b795450641950b71958" + integrity sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-async-generator-functions@^7.22.7": + version "7.22.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.7.tgz#053e76c0a903b72b573cb1ab7d6882174d460a1b" + integrity sha512-7HmE7pk/Fmke45TODvxvkxRMV9RazV+ZZzhOL9AG8G29TLrr3jkjwF7uJfxZ30EoXpO+LJkq4oA8NjO2DTnEDg== + dependencies: + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + "@babel/plugin-syntax-async-generators" "^7.8.4" + +"@babel/plugin-transform-async-to-generator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.22.5.tgz#c7a85f44e46f8952f6d27fe57c2ed3cc084c3775" + integrity sha512-b1A8D8ZzE/VhNDoV1MSJTnpKkCG5bJo+19R4o4oy03zM7ws8yEMK755j61Dc3EyvdysbqH5BOOTquJ7ZX9C6vQ== + dependencies: + "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-remap-async-to-generator" "^7.22.5" + +"@babel/plugin-transform-block-scoped-functions@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz#27978075bfaeb9fa586d3cb63a3d30c1de580024" + integrity sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-block-scoping@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.5.tgz#8bfc793b3a4b2742c0983fadc1480d843ecea31b" + integrity sha512-EcACl1i5fSQ6bt+YGuU/XGCeZKStLmyVGytWkpyhCLeQVA0eu6Wtiw92V+I1T/hnezUv7j74dA/Ro69gWcU+hg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.22.5.tgz#97a56e31ad8c9dc06a0b3710ce7803d5a48cca77" + integrity sha512-nDkQ0NfkOhPTq8YCLiWNxp1+f9fCobEjCb0n8WdbNUBc4IB5V7P1QnX9IjpSoquKrXF5SKojHleVNs2vGeHCHQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-class-static-block@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.22.5.tgz#3e40c46f048403472d6f4183116d5e46b1bff5ba" + integrity sha512-SPToJ5eYZLxlnp1UzdARpOGeC2GbHvr9d/UV0EukuVx8atktg194oe+C5BqQ8jRTkgLRVOPYeXRSBg1IlMoVRA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + +"@babel/plugin-transform-classes@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363" + integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-optimise-call-expression" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + globals "^11.1.0" + +"@babel/plugin-transform-computed-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz#cd1e994bf9f316bd1c2dafcd02063ec261bb3869" + integrity sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/template" "^7.22.5" + +"@babel/plugin-transform-destructuring@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.5.tgz#d3aca7438f6c26c78cdd0b0ba920a336001b27cc" + integrity sha512-GfqcFuGW8vnEqTUBM7UtPd5A4q797LTvvwKxXTgRsFjoqaJiEg9deBG6kWeQYkVEL569NpnmpC0Pkr/8BLKGnQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dotall-regex@^7.22.5", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.22.5.tgz#dbb4f0e45766eb544e193fb00e65a1dd3b2a4165" + integrity sha512-5/Yk9QxCQCl+sOIB1WelKnVRxTJDSAIxtJLL2/pqL14ZVlbH0fUQUZa/T5/UnQtBNgghR7mfB8ERBKyKPCi7Vw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-duplicate-keys@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.22.5.tgz#b6e6428d9416f5f0bba19c70d1e6e7e0b88ab285" + integrity sha512-dEnYD+9BBgld5VBXHnF/DbYGp3fqGMsyxKbtD1mDyIA7AkTSpKXFhCVuj/oQVOoALfBs77DudA0BE4d5mcpmqw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-dynamic-import@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.22.5.tgz#d6908a8916a810468c4edff73b5b75bda6ad393e" + integrity sha512-0MC3ppTB1AMxd8fXjSrbPa7LT9hrImt+/fcj+Pg5YMD7UQyWp/02+JWpdnCymmsXwIx5Z+sYn1bwCn4ZJNvhqQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + +"@babel/plugin-transform-exponentiation-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.22.5.tgz#402432ad544a1f9a480da865fda26be653e48f6a" + integrity sha512-vIpJFNM/FjZ4rh1myqIya9jXwrwwgFRHPjT3DkUA9ZLHuzox8jiXkOLvwm1H+PQIP3CqfC++WPKeuDi0Sjdj1g== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-export-namespace-from@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.22.5.tgz#57c41cb1d0613d22f548fddd8b288eedb9973a5b" + integrity sha512-X4hhm7FRnPgd4nDA4b/5V280xCx6oL7Oob5+9qVS5C13Zq4bh1qq7LU0GgRU6b5dBWBvhGaXYVB4AcN6+ol6vg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + +"@babel/plugin-transform-for-of@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f" + integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-function-name@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz#935189af68b01898e0d6d99658db6b164205c143" + integrity sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg== + dependencies: + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-json-strings@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.22.5.tgz#14b64352fdf7e1f737eed68de1a1468bd2a77ec0" + integrity sha512-DuCRB7fu8MyTLbEQd1ew3R85nx/88yMoqo2uPSjevMj3yoN7CDM8jkgrY0wmVxfJZyJ/B9fE1iq7EQppWQmR5A== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-json-strings" "^7.8.3" + +"@babel/plugin-transform-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz#e9341f4b5a167952576e23db8d435849b1dd7920" + integrity sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-logical-assignment-operators@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.22.5.tgz#66ae5f068fd5a9a5dc570df16f56c2a8462a9d6c" + integrity sha512-MQQOUW1KL8X0cDWfbwYP+TbVbZm16QmQXJQ+vndPtH/BoO0lOKpVoEDMI7+PskYxH+IiE0tS8xZye0qr1lGzSA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + +"@babel/plugin-transform-member-expression-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz#4fcc9050eded981a468347dd374539ed3e058def" + integrity sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-amd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.22.5.tgz#4e045f55dcf98afd00f85691a68fc0780704f526" + integrity sha512-R+PTfLTcYEmb1+kK7FNkhQ1gP4KgjpSO6HfH9+f8/yfp2Nt3ggBjiVpRwmwTlfqZLafYKJACy36yDXlEmI9HjQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-modules-commonjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.5.tgz#7d9875908d19b8c0536085af7b053fd5bd651bfa" + integrity sha512-B4pzOXj+ONRmuaQTg05b3y/4DuFz3WcCNAXPLb2Q0GT0TrGKGxNKV4jwsXts+StaM0LQczZbOpj8o1DLPDJIiA== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-simple-access" "^7.22.5" + +"@babel/plugin-transform-modules-systemjs@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.22.5.tgz#18c31410b5e579a0092638f95c896c2a98a5d496" + integrity sha512-emtEpoaTMsOs6Tzz+nbmcePl6AKVtS1yC4YNAeMun9U8YCsgadPNxnOPQ8GhHFB2qdx+LZu9LgoC0Lthuu05DQ== + dependencies: + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + +"@babel/plugin-transform-modules-umd@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.22.5.tgz#4694ae40a87b1745e3775b6a7fe96400315d4f98" + integrity sha512-+S6kzefN/E1vkSsKx8kmQuqeQsvCKCd1fraCM7zXm4SFoggI099Tr4G8U81+5gtMdUeMQ4ipdQffbKLX0/7dBQ== + dependencies: + "@babel/helper-module-transforms" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz#67fe18ee8ce02d57c855185e27e3dc959b2e991f" + integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-new-target@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.22.5.tgz#1b248acea54ce44ea06dfd37247ba089fcf9758d" + integrity sha512-AsF7K0Fx/cNKVyk3a+DW0JLo+Ua598/NxMRvxDnkpCIGFh43+h/v2xyhRUYf6oD8gE4QtL83C7zZVghMjHd+iw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-nullish-coalescing-operator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.22.5.tgz#f8872c65776e0b552e0849d7596cddd416c3e381" + integrity sha512-6CF8g6z1dNYZ/VXok5uYkkBBICHZPiGEl7oDnAx2Mt1hlHVHOSIKWJaXHjQJA5VB43KZnXZDIexMchY4y2PGdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + +"@babel/plugin-transform-numeric-separator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.22.5.tgz#57226a2ed9e512b9b446517ab6fa2d17abb83f58" + integrity sha512-NbslED1/6M+sXiwwtcAB/nieypGw02Ejf4KtDeMkCEpP6gWFMX1wI9WKYua+4oBneCCEmulOkRpwywypVZzs/g== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + +"@babel/plugin-transform-object-rest-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.5.tgz#9686dc3447df4753b0b2a2fae7e8bc33cdc1f2e1" + integrity sha512-Kk3lyDmEslH9DnvCDA1s1kkd3YWQITiBOHngOtDL9Pt6BZjzqb6hiOlb8VfjiiQJ2unmegBqZu0rx5RxJb5vmQ== + dependencies: + "@babel/compat-data" "^7.22.5" + "@babel/helper-compilation-targets" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.22.5" + +"@babel/plugin-transform-object-super@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz#794a8d2fcb5d0835af722173c1a9d704f44e218c" + integrity sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.5" + +"@babel/plugin-transform-optional-catch-binding@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.22.5.tgz#842080be3076703be0eaf32ead6ac8174edee333" + integrity sha512-pH8orJahy+hzZje5b8e2QIlBWQvGpelS76C63Z+jhZKsmzfNaPQ+LaW6dcJ9bxTpo1mtXbgHwy765Ro3jftmUg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + +"@babel/plugin-transform-optional-chaining@^7.22.5", "@babel/plugin-transform-optional-chaining@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.6.tgz#4bacfe37001fe1901117672875e931d439811564" + integrity sha512-Vd5HiWml0mDVtcLHIoEU5sw6HOUW/Zk0acLs/SAeuLzkGNOPc9DB4nkUajemhCmTIz3eiaKREZn2hQQqF79YTg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + +"@babel/plugin-transform-parameters@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" + integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-methods@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.22.5.tgz#21c8af791f76674420a147ae62e9935d790f8722" + integrity sha512-PPjh4gyrQnGe97JTalgRGMuU4icsZFnWkzicB/fUtzlKUqvsWBKEpPPfr5a2JiyirZkHxnAqkQMO5Z5B2kK3fA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-private-property-in-object@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.22.5.tgz#07a77f28cbb251546a43d175a1dda4cf3ef83e32" + integrity sha512-/9xnaTTJcVoBtSSmrVyhtSvO3kbqS2ODoh2juEU72c3aYonNF0OMGiaz2gjukyKM2wBBYJP38S4JiE0Wfb5VMQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + +"@babel/plugin-transform-property-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz#b5ddabd73a4f7f26cd0e20f5db48290b88732766" + integrity sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-regenerator@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.22.5.tgz#cd8a68b228a5f75fa01420e8cc2fc400f0fc32aa" + integrity sha512-rR7KePOE7gfEtNTh9Qw+iO3Q/e4DEsoQ+hdvM6QUDH7JRJ5qxq5AA52ZzBWbI5i9lfNuvySgOGP8ZN7LAmaiPw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + regenerator-transform "^0.15.1" + +"@babel/plugin-transform-reserved-words@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.22.5.tgz#832cd35b81c287c4bcd09ce03e22199641f964fb" + integrity sha512-DTtGKFRQUDm8svigJzZHzb/2xatPc6TzNvAIJ5GqOKDsGFYgAskjRulbR/vGsPKq3OPqtexnz327qYpP57RFyA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-shorthand-properties@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz#6e277654be82b5559fc4b9f58088507c24f0c624" + integrity sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-spread@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz#6487fd29f229c95e284ba6c98d65eafb893fea6b" + integrity sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + +"@babel/plugin-transform-sticky-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.22.5.tgz#295aba1595bfc8197abd02eae5fc288c0deb26aa" + integrity sha512-zf7LuNpHG0iEeiyCNwX4j3gDg1jgt1k3ZdXBKbZSoA3BbGQGvMiSvfbZRR3Dr3aeJe3ooWFZxOOG3IRStYp2Bw== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-template-literals@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz#8f38cf291e5f7a8e60e9f733193f0bcc10909bff" + integrity sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typeof-symbol@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.22.5.tgz#5e2ba478da4b603af8673ff7c54f75a97b716b34" + integrity sha512-bYkI5lMzL4kPii4HHEEChkD0rkc+nvnlR6+o/qdqR6zrm0Sv/nodmyLhlq2DO0YKLUNd2VePmPRjJXSBh9OIdA== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-typescript@^7.22.5": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.9.tgz#91e08ad1eb1028ecc62662a842e93ecfbf3c7234" + integrity sha512-BnVR1CpKiuD0iobHPaM1iLvcwPYN2uVFAqoLVSpEDKWuOikoCv5HbKLxclhKYUXlWkX86DoZGtqI4XhbOsyrMg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.22.5" + "@babel/helper-create-class-features-plugin" "^7.22.9" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/plugin-syntax-typescript" "^7.22.5" + +"@babel/plugin-transform-unicode-escapes@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.22.5.tgz#ce0c248522b1cb22c7c992d88301a5ead70e806c" + integrity sha512-biEmVg1IYB/raUO5wT1tgfacCef15Fbzhkx493D3urBI++6hpJ+RFG4SrWMn0NEZLfvilqKf3QDrRVZHo08FYg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-property-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.22.5.tgz#098898f74d5c1e86660dc112057b2d11227f1c81" + integrity sha512-HCCIb+CbJIAE6sXn5CjFQXMwkCClcOfPCzTlilJ8cUatfzwHlWQkbtV0zD338u9dZskwvuOYTuuaMaA8J5EI5A== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.22.5.tgz#ce7e7bb3ef208c4ff67e02a22816656256d7a183" + integrity sha512-028laaOKptN5vHJf9/Arr/HiJekMd41hOEZYvNsrsXqJ7YPYuX2bQxh31fkZzGmq3YqHRJzYFFAVYvKfMPKqyg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-transform-unicode-sets-regex@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.22.5.tgz#77788060e511b708ffc7d42fdfbc5b37c3004e91" + integrity sha512-lhMfi4FC15j13eKrh3DnYHjpGj6UKQHtNKTbtc1igvAhRy4+kLhV07OpLcsN0VgDEw/MjAvJO4BdMJsHwMhzCg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.22.5" + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/preset-env@^7.19.1": + version "7.22.9" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.9.tgz#57f17108eb5dfd4c5c25a44c1977eba1df310ac7" + integrity sha512-wNi5H/Emkhll/bqPjsjQorSykrlfY5OWakd6AulLvMEytpKasMVUpVy8RL4qBIBs5Ac6/5i0/Rv0b/Fg6Eag/g== + dependencies: + "@babel/compat-data" "^7.22.9" + "@babel/helper-compilation-targets" "^7.22.9" + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5" + "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-import-assertions" "^7.22.5" + "@babel/plugin-syntax-import-attributes" "^7.22.5" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" + "@babel/plugin-transform-arrow-functions" "^7.22.5" + "@babel/plugin-transform-async-generator-functions" "^7.22.7" + "@babel/plugin-transform-async-to-generator" "^7.22.5" + "@babel/plugin-transform-block-scoped-functions" "^7.22.5" + "@babel/plugin-transform-block-scoping" "^7.22.5" + "@babel/plugin-transform-class-properties" "^7.22.5" + "@babel/plugin-transform-class-static-block" "^7.22.5" + "@babel/plugin-transform-classes" "^7.22.6" + "@babel/plugin-transform-computed-properties" "^7.22.5" + "@babel/plugin-transform-destructuring" "^7.22.5" + "@babel/plugin-transform-dotall-regex" "^7.22.5" + "@babel/plugin-transform-duplicate-keys" "^7.22.5" + "@babel/plugin-transform-dynamic-import" "^7.22.5" + "@babel/plugin-transform-exponentiation-operator" "^7.22.5" + "@babel/plugin-transform-export-namespace-from" "^7.22.5" + "@babel/plugin-transform-for-of" "^7.22.5" + "@babel/plugin-transform-function-name" "^7.22.5" + "@babel/plugin-transform-json-strings" "^7.22.5" + "@babel/plugin-transform-literals" "^7.22.5" + "@babel/plugin-transform-logical-assignment-operators" "^7.22.5" + "@babel/plugin-transform-member-expression-literals" "^7.22.5" + "@babel/plugin-transform-modules-amd" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-modules-systemjs" "^7.22.5" + "@babel/plugin-transform-modules-umd" "^7.22.5" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" + "@babel/plugin-transform-new-target" "^7.22.5" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.5" + "@babel/plugin-transform-numeric-separator" "^7.22.5" + "@babel/plugin-transform-object-rest-spread" "^7.22.5" + "@babel/plugin-transform-object-super" "^7.22.5" + "@babel/plugin-transform-optional-catch-binding" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.6" + "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-private-methods" "^7.22.5" + "@babel/plugin-transform-private-property-in-object" "^7.22.5" + "@babel/plugin-transform-property-literals" "^7.22.5" + "@babel/plugin-transform-regenerator" "^7.22.5" + "@babel/plugin-transform-reserved-words" "^7.22.5" + "@babel/plugin-transform-shorthand-properties" "^7.22.5" + "@babel/plugin-transform-spread" "^7.22.5" + "@babel/plugin-transform-sticky-regex" "^7.22.5" + "@babel/plugin-transform-template-literals" "^7.22.5" + "@babel/plugin-transform-typeof-symbol" "^7.22.5" + "@babel/plugin-transform-unicode-escapes" "^7.22.5" + "@babel/plugin-transform-unicode-property-regex" "^7.22.5" + "@babel/plugin-transform-unicode-regex" "^7.22.5" + "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.22.5" + babel-plugin-polyfill-corejs2 "^0.4.4" + babel-plugin-polyfill-corejs3 "^0.8.2" + babel-plugin-polyfill-regenerator "^0.5.1" + core-js-compat "^3.31.0" + semver "^6.3.1" + +"@babel/preset-modules@^0.1.5": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6.tgz#31bcdd8f19538437339d17af00d177d854d9d458" + integrity sha512-ID2yj6K/4lKfhuU3+EX4UvNbIt7eACFbHmNUjzA+ep+B5971CknnA/9DEWKbRokfbbtblxxxXFJJrH47UEAMVg== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + +"@babel/preset-typescript@^7.18.6": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.22.5.tgz#16367d8b01d640e9a507577ed4ee54e0101e51c8" + integrity sha512-YbPaal9LxztSGhmndR46FmAbkJ/1fAsw293tSU+I5E5h+cnJ3d4GTwyUgGYmOXJYdGA+uNePle4qbaRzj2NISQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-validator-option" "^7.22.5" + "@babel/plugin-syntax-jsx" "^7.22.5" + "@babel/plugin-transform-modules-commonjs" "^7.22.5" + "@babel/plugin-transform-typescript" "^7.22.5" + +"@babel/regjsgen@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" + integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== + +"@babel/runtime@^7.8.4": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.6.tgz#57d64b9ae3cff1d67eb067ae117dac087f5bd438" + integrity sha512-wDb5pWm4WDdF6LFUde3Jl8WzPA+3ZbxYqkC6xAXuD3irdEHN1k0NfTRrJD8ZD378SJ61miMLCqIOXYhd8x+AJQ== + dependencies: + regenerator-runtime "^0.13.11" + +"@babel/template@^7.22.5", "@babel/template@^7.3.3", "@babel/template@^7.4.4": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" + integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/parser" "^7.22.5" + "@babel/types" "^7.22.5" + +"@babel/traverse@^7.22.6", "@babel/traverse@^7.22.8": + version "7.22.8" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.8.tgz#4d4451d31bc34efeae01eac222b514a77aa4000e" + integrity sha512-y6LPR+wpM2I3qJrsheCTwhIinzkETbplIgPBbwvqPKc+uljeA5gP+3nP8irdYt1mjQaDnlIcG+dw8OjAco4GXw== + dependencies: + "@babel/code-frame" "^7.22.5" + "@babel/generator" "^7.22.7" + "@babel/helper-environment-visitor" "^7.22.5" + "@babel/helper-function-name" "^7.22.5" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.22.7" + "@babel/types" "^7.22.5" + debug "^4.1.0" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.5.tgz#cd93eeaab025880a3a47ec881f4b096a5b786fbe" + integrity sha512-zo3MIHGOkPOfoRXitsgHLjEXmlDaD/5KU1Uzuc9GNiZPhSqVxVRtxuPaSBZDsYZ9qV88AjtMtWW7ww98loJ9KA== + dependencies: + "@babel/helper-string-parser" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.5" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@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== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@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" + +"@eslint-community/eslint-utils@^4.2.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": + version "4.6.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" + integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== + +"@eslint/eslintrc@^2.1.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.1.tgz#18d635e24ad35f7276e8a49d135c7d3ca6a46f93" + integrity sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@^8.46.0": + version "8.46.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.46.0.tgz#3f7802972e8b6fe3f88ed1aabc74ec596c456db6" + integrity sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA== + +"@ethereumjs/common@2.5.0": + version "2.5.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.5.0.tgz#ec61551b31bef7a69d1dc634d8932468866a4268" + integrity sha512-DEHjW6e38o+JmB/NO3GZBpW4lpaiBpkFgXF6jLcJ6gETBYpEyaA5nTimsWBUJR3Vmtm/didUEbNjajskugZORg== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.1" + +"@ethereumjs/common@^2.5.0": + version "2.6.5" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.5.tgz#0a75a22a046272579d91919cb12d84f2756e8d30" + integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.5" + +"@ethereumjs/tx@3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.3.2.tgz#348d4624bf248aaab6c44fec2ae67265efe3db00" + integrity sha512-6AaJhwg4ucmwTvw/1qLaZUX5miWrwZ4nLOUsKyb/HtzS3BMw/CasKhdi1ims9mBKeK9sOJCH4qGKOBGyJCeeog== + dependencies: + "@ethereumjs/common" "^2.5.0" + ethereumjs-util "^7.1.2" + +"@ethersproject/abi@^5.6.3": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.7.0.tgz#b3f3e045bbbeed1af3947335c247ad625a44e449" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz#b0a8550f88b6bf9d51f90e4795d48294630cb9ef" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz#13f4f32117868452191a4649723cb086d2b596b2" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.7.0.tgz#19b56c4d74a3b0a46bfdbb6cfcc0a153fc697f37" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.7.0.tgz#ac4ee92aa36c1628173e221d0d01f53692059e1c" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/bignumber@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.7.0.tgz#e2f03837f268ba655ffba03a57853e18a18dc9c2" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.7.0.tgz#a00f6ea8d7e7534d6d87f47188af1148d71f155d" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.7.0.tgz#df80a9705a7e08984161f09014ea012d1c75295e" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/hash@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.7.0.tgz#eb7aca84a588508369562e16e514b539ba5240a7" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/keccak256@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.7.0.tgz#3186350c6e1cd6aba7940384ec7d6d9db01f335a" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.7.0.tgz#6ce9ae168e74fecf287be17062b590852c311892" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.7.1.tgz#118e1a981d757d45ccea6bb58d9fd3d9db14ead6" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/properties@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.7.0.tgz#a6e12cb0439b878aaf470f1902a176033067ed30" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.7.0.tgz#de39e4d5918b9d74d46de93af80b7685a9c21304" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/signing-key@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.7.0.tgz#06b2df39411b00bc57c7c09b01d1e41cf1b16ab3" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/strings@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.7.0.tgz#54c9d2a7c57ae8f1205c88a9d3a56471e14d5ed2" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@^5.6.2", "@ethersproject/transactions@^5.7.0": + version "5.7.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.7.0.tgz#91318fc24063e057885a6af13fdb703e1f993d3b" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/web@^5.7.0": + version "5.7.1" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.7.1.tgz#de1f285b373149bee5928f4eb7bcb87ee5fbb4ae" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@humanwhocodes/config-array@^0.11.10": + version "0.11.10" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.10.tgz#5a3ffe32cc9306365fb3fd572596cd602d5e12d2" + integrity sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.6.2.tgz#bf1d4101347c23e07c029a1b1ae07d550f5cc541" + integrity sha512-0N0yZof5hi44HAR2pPS+ikJ3nzKNoZdVu8FffRf3wy47I7Dm7etk/3KetMdRUqzVd16V4O2m2ISpNTbnIuqy1w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + +"@jest/core@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.6.2.tgz#6f2d1dbe8aa0265fcd4fb8082ae1952f148209c8" + integrity sha512-Oj+5B+sDMiMWLhPFF+4/DvHOf+U10rgvCLGPHP8Xlsy/7QxS51aU/eBngudHlJXnaWD5EohAgJ4js+T6pa+zOg== + dependencies: + "@jest/console" "^29.6.2" + "@jest/reporters" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.5.0" + jest-config "^29.6.2" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-resolve-dependencies "^29.6.2" + jest-runner "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + jest-watcher "^29.6.2" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.6.2.tgz#794c0f769d85e7553439d107d3f43186dc6874a9" + integrity sha512-AEcW43C7huGd/vogTddNNTDRpO6vQ2zaQNrttvWV18ArBx9Z56h7BIsXkNFJVOO4/kblWEQz30ckw0+L3izc+Q== + dependencies: + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + +"@jest/expect-utils@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.6.2.tgz#1b97f290d0185d264dd9fdec7567a14a38a90534" + integrity sha512-6zIhM8go3RV2IG4aIZaZbxwpOzz3ZiM23oxAlkquOIole+G6TrbeXnykxWYlqF7kz2HlBjdKtca20x9atkEQYg== + dependencies: + jest-get-type "^29.4.3" + +"@jest/expect@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.6.2.tgz#5a2ad58bb345165d9ce0a1845bbf873c480a4b28" + integrity sha512-m6DrEJxVKjkELTVAztTLyS/7C92Y2b0VYqmDROYKLLALHn8T/04yPs70NADUYPrV3ruI+H3J0iUIuhkjp7vkfg== + dependencies: + expect "^29.6.2" + jest-snapshot "^29.6.2" + +"@jest/fake-timers@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.6.2.tgz#fe9d43c5e4b1b901168fe6f46f861b3e652a2df4" + integrity sha512-euZDmIlWjm1Z0lJ1D0f7a0/y5Kh/koLFMUBE5SUYWrmy8oNhJpbTBDAP6CxKnadcMLDoDf4waRYCe35cH6G6PA== + dependencies: + "@jest/types" "^29.6.1" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-util "^29.6.2" + +"@jest/globals@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.6.2.tgz#74af81b9249122cc46f1eb25793617eec69bf21a" + integrity sha512-cjuJmNDjs6aMijCmSa1g2TNG4Lby/AeU7/02VtpW+SLcZXzOLK2GpN2nLqcFjmhy3B3AoPeQVx7BnyOf681bAw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/types" "^29.6.1" + jest-mock "^29.6.2" + +"@jest/reporters@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.6.2.tgz#524afe1d76da33d31309c2c4a2c8062d0c48780a" + integrity sha512-sWtijrvIav8LgfJZlrGCdN0nP2EWbakglJY49J1Y5QihcQLfy7ovyxxjJBRXMNltgt4uPtEcFmIMbVshEDfFWw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^5.1.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + jest-worker "^29.6.2" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.0.tgz#0f4cb2c8e3dca80c135507ba5635a4fd755b0040" + integrity sha512-rxLjXyJBTL4LQeJW3aKo0M/+GkCOXsO+8i9Iu7eDb6KwtP65ayoDsitrdPBtujxQ88k4wI2FNYfa6TOGwSn6cQ== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.0": + version "29.6.0" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.0.tgz#bd34a05b5737cb1a99d43e1957020ac8e5b9ddb1" + integrity sha512-oA+I2SHHQGxDCZpbrsCQSoMLb3Bz547JnM+jUr9qEbuw0vQlWZfpPS7CO9J7XiwKicEz9OFn/IYoLkkiUD7bzA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.6.2.tgz#fdd11583cd1608e4db3114e8f0cce277bf7a32ed" + integrity sha512-3VKFXzcV42EYhMCsJQURptSqnyjqCGbtLuX5Xxb6Pm6gUf1wIRIl+mandIRGJyWKgNKYF9cnstti6Ls5ekduqw== + dependencies: + "@jest/console" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.6.2.tgz#585eff07a68dd75225a7eacf319780cb9f6b9bf4" + integrity sha512-GVYi6PfPwVejO7slw6IDO0qKVum5jtrJ3KoLGbgBWyr2qr4GaxFV6su+ZAjdTX75Sr1DkMFRk09r2ZVa+wtCGw== + dependencies: + "@jest/test-result" "^29.6.2" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + slash "^3.0.0" + +"@jest/transform@^29.6.2": + version "29.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.6.2.tgz#522901ebbb211af08835bc3bcdf765ab778094e3" + integrity sha512-ZqCqEISr58Ce3U+buNFJYUktLJZOggfyvR+bZMaiV1e8B1SIvJbwZMrYz3gx/KAPn9EXmOmN+uB08yLCjWkQQg== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.1" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.1": + version "29.6.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.1.tgz#ae79080278acff0a6af5eb49d063385aaa897bf2" + integrity sha512-tPKQNMPuXgvdOn2/Lg9HNfUvjYVGolt04Hp03f5hAk878uwOLikN+JzeLY0HcVgKgFl9Hs3EIqpu3WX27XNhnw== + dependencies: + "@jest/schemas" "^29.6.0" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" + integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== + +"@jridgewell/resolve-uri@^3.0.3": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@1.4.14": + version "1.4.14" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" + integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== + +"@jridgewell/sourcemap-codec@^1.4.10": + 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.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + +"@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", "@nodelib/fs.walk@^1.2.8": + 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" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@sentry-internal/tracing@7.61.1": + version "7.61.1" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.61.1.tgz#8055b7dfbf89b7089a591b27e05484d5f6773948" + integrity sha512-E8J6ZMXHGdWdmgKBK/ounuUppDK65c4Hphin6iVckDGMEATn0auYAKngeyRUMLof1167DssD8wxcIA4aBvmScA== + dependencies: + "@sentry/core" "7.61.1" + "@sentry/types" "7.61.1" + "@sentry/utils" "7.61.1" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/core@7.61.1": + version "7.61.1" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.61.1.tgz#8043c7cecf5ca0601f6c61979fb2880ceac37287" + integrity sha512-WTRt0J33KhUbYuDQZ5G58kdsNeQ5JYrpi6o+Qz+1xTv60DQq/tBGRJ7d86SkmdnGIiTs6W1hsxAtyiLS0y9d2A== + dependencies: + "@sentry/types" "7.61.1" + "@sentry/utils" "7.61.1" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/node@^7.1.1": + version "7.61.1" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.61.1.tgz#bc49d321d0a511936f8bdd0bbd3ddc5e01b8d98c" + integrity sha512-+crVAeymXdWZcDuwU9xySf4sVv2fHOFlr13XqeXl73q4zqKJM1IX4VUO9On3+jTyGfB5SCAuBBYpzA3ehBfeYw== + dependencies: + "@sentry-internal/tracing" "7.61.1" + "@sentry/core" "7.61.1" + "@sentry/types" "7.61.1" + "@sentry/utils" "7.61.1" + cookie "^0.4.1" + https-proxy-agent "^5.0.0" + lru_map "^0.3.3" + tslib "^2.4.1 || ^1.9.3" + +"@sentry/types@7.61.1": + version "7.61.1" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.61.1.tgz#225912689459c92e62f0b6e3ff145f6dbf72ff0e" + integrity sha512-CpPKL+OfwYOduRX9AT3p+Ie1fftgcCPd5WofTVVq7xeWRuerOOf2iJd0v+8yHQ25omgres1YOttDkCcvQRn4Jw== + +"@sentry/utils@7.61.1": + version "7.61.1" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.61.1.tgz#1545db778b7309d122a7f04eb0e803173c80c581" + integrity sha512-pUPXoiuYrTEPcBHjRizFB6eZEGm/6cTBwdWSHUjkGKvt19zuZ1ixFJQV6LrIL/AMeiQbmfQ+kTd/8SR7E9rcTQ== + dependencies: + "@sentry/types" "7.61.1" + tslib "^2.4.1 || ^1.9.3" + +"@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== + +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@smithy/abort-controller@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-2.0.1.tgz#ddb5dd8c37016e8fcf772bd9c80e900860d74ae6" + integrity sha512-0s7XjIbsTwZyUW9OwXQ8J6x1UiA1TNCh60Vaw56nHahL7kUZsLhmTlWiaxfLkFtO2Utkj8YewcpHTYpxaTzO+w== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/config-resolver@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-2.0.1.tgz#ea7981f4716961889d1c7d16aaa956cf7dae2b79" + integrity sha512-l83Pm7hV+8CBQOCmBRopWDtF+CURUJol7NsuPYvimiDhkC2F8Ba9T1imSFE+pD1UIJ9jlsDPAnZfPJT5cjnuEw== + dependencies: + "@smithy/types" "^2.0.2" + "@smithy/util-config-provider" "^2.0.0" + "@smithy/util-middleware" "^2.0.0" + tslib "^2.5.0" + +"@smithy/credential-provider-imds@^2.0.0", "@smithy/credential-provider-imds@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.1.tgz#e034f3d8ee6ad178becb267886056233870661d0" + integrity sha512-8VxriuRINNEfVZjEFKBY75y9ZWAx73DZ5K/u+3LmB6r8WR2h3NaFxFKMlwlq0uzNdGhD1ouKBn9XWEGYHKiPLw== + dependencies: + "@smithy/node-config-provider" "^2.0.1" + "@smithy/property-provider" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/url-parser" "^2.0.1" + tslib "^2.5.0" + +"@smithy/eventstream-codec@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-2.0.1.tgz#b84e224db346066e817ca9ca23260798a1aa071e" + integrity sha512-/IiNB7gQM2y2ZC/GAWOWDa8+iXfhr1g9Xe5979cQEOdCWDISvrAiv18cn3OtIQUhbYOR3gm7QtCpkq1to2takQ== + dependencies: + "@aws-crypto/crc32" "3.0.0" + "@smithy/types" "^2.0.2" + "@smithy/util-hex-encoding" "^2.0.0" + tslib "^2.5.0" + +"@smithy/fetch-http-handler@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-2.0.1.tgz#5c8903897d3fd7ae3758ed7760d559d72d27e902" + integrity sha512-/SoU/ClazgcdOxgE4zA7RX8euiELwpsrKCSvulVQvu9zpmqJRyEJn8ZTWYFV17/eHOBdHTs9kqodhNhsNT+cUw== + dependencies: + "@smithy/protocol-http" "^2.0.1" + "@smithy/querystring-builder" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/util-base64" "^2.0.0" + tslib "^2.5.0" + +"@smithy/hash-node@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-2.0.1.tgz#458b74378cbfecf6dcd1ffc6b7ec7d29a4247efd" + integrity sha512-oTKYimQdF4psX54ZonpcIE+MXjMUWFxLCNosjPkJPFQ9whRX0K/PFX/+JZGRQh3zO9RlEOEUIbhy9NO+Wha6hw== + dependencies: + "@smithy/types" "^2.0.2" + "@smithy/util-buffer-from" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/invalid-dependency@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-2.0.1.tgz#bb49b297e2141ec2ba6e131e0946af0ba59509e2" + integrity sha512-2q/Eb0AE662zwyMV+z+TL7deBwcHCgaZZGc0RItamBE8kak3MzCi/EZCNoFWoBfxgQ4jfR12wm8KKsSXhJzJtQ== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/is-array-buffer@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz#8fa9b8040651e7ba0b2f6106e636a91354ff7d34" + integrity sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug== + dependencies: + tslib "^2.5.0" + +"@smithy/middleware-content-length@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-2.0.1.tgz#86005cd4cb45eff5420730abe88e08d22c582d79" + integrity sha512-IZhRSk5GkVBcrKaqPXddBS2uKhaqwBgaSgbBb1OJyGsKe7SxRFbclWS0LqOR9fKUkDl+3lL8E2ffpo6EQg0igw== + dependencies: + "@smithy/protocol-http" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/middleware-endpoint@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.1.tgz#4e992dd2c9dedbff776150045904c5455df4eaf7" + integrity sha512-uz/KI1MBd9WHrrkVFZO4L4Wyv24raf0oR4EsOYEeG5jPJO5U+C7MZGLcMxX8gWERDn1sycBDqmGv8fjUMLxT6w== + dependencies: + "@smithy/middleware-serde" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/url-parser" "^2.0.1" + "@smithy/util-middleware" "^2.0.0" + tslib "^2.5.0" + +"@smithy/middleware-retry@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-2.0.1.tgz#d6c0aa9d117140a429951c8a1a92e05d9d0c218c" + integrity sha512-NKHF4i0gjSyjO6C0ZyjEpNqzGgIu7s8HOK6oT/1Jqws2Q1GynR1xV8XTUs1gKXeaNRzbzKQRewHHmfPwZjOtHA== + dependencies: + "@smithy/protocol-http" "^2.0.1" + "@smithy/service-error-classification" "^2.0.0" + "@smithy/types" "^2.0.2" + "@smithy/util-middleware" "^2.0.0" + "@smithy/util-retry" "^2.0.0" + tslib "^2.5.0" + uuid "^8.3.2" + +"@smithy/middleware-serde@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-2.0.1.tgz#daa38ebc5873f1f7d0430e7a75b7255b69c70016" + integrity sha512-uKxPaC6ItH9ZXdpdqNtf8sda7GcU4SPMp0tomq/5lUg9oiMa/Q7+kD35MUrpKaX3IVXVrwEtkjCU9dogZ/RAUA== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/middleware-stack@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-2.0.0.tgz#cd9f442c2788b1ef0ea6b32236d80c76b3c342e9" + integrity sha512-31XC1xNF65nlbc16yuh3wwTudmqs6qy4EseQUGF8A/p2m/5wdd/cnXJqpniy/XvXVwkHPz/GwV36HqzHtIKATQ== + dependencies: + tslib "^2.5.0" + +"@smithy/node-config-provider@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-2.0.1.tgz#5a17c2564dc9689d523408c9a6dea9ca1330c47f" + integrity sha512-Zoel4CPkKRTQ2XxmozZUfqBYqjPKL53/SvTDhJHj+VBSiJy6MXRav1iDCyFPS92t40Uh+Yi+Km5Ch3hQ+c/zSA== + dependencies: + "@smithy/property-provider" "^2.0.1" + "@smithy/shared-ini-file-loader" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/node-http-handler@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-2.0.1.tgz#7a1b23e30c5125ec31062a8b5edbc9fdd96ac651" + integrity sha512-Zv3fxk3p9tsmPT2CKMsbuwbbxnq2gzLDIulxv+yI6aE+02WPYorObbbe9gh7SW3weadMODL1vTfOoJ9yFypDzg== + dependencies: + "@smithy/abort-controller" "^2.0.1" + "@smithy/protocol-http" "^2.0.1" + "@smithy/querystring-builder" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/property-provider@^2.0.0", "@smithy/property-provider@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-2.0.1.tgz#4c359f5063a9c664599f88be00e3f9b3e1021d4d" + integrity sha512-pmJRyY9SF6sutWIktIhe+bUdSQDxv/qZ4mYr3/u+u45riTPN7nmRxPo+e4sjWVoM0caKFjRSlj3tf5teRFy0Vg== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/protocol-http@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-2.0.1.tgz#4257b9b8803f1e7638022a9cc6be8ea0abacac26" + integrity sha512-mrkMAp0wtaDEIkgRObWYxI1Kun1tm6Iu6rK+X4utb6Ah7Uc3Kk4VIWwK/rBHdYGReiLIrxFCB1rq4a2gyZnSgg== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/querystring-builder@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-2.0.1.tgz#c8326d27e3796cac8b46f580bb067e83f50b4375" + integrity sha512-bp+93WFzx1FojVEIeFPtG0A1pKsFdCUcZvVdZdRlmNooOUrz9Mm9bneRd8hDwAQ37pxiZkCOxopSXXRQN10mYw== + dependencies: + "@smithy/types" "^2.0.2" + "@smithy/util-uri-escape" "^2.0.0" + tslib "^2.5.0" + +"@smithy/querystring-parser@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-2.0.1.tgz#915872aa7983218da3e87144a5b729dd6ae6f50f" + integrity sha512-h+e7k1z+IvI2sSbUBG9Aq46JsgLl4UqIUl6aigAlRBj+P6ocNXpM6Yn1vMBw5ijtXeZbYpd1YvCxwDgdw3jhmg== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/service-error-classification@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-2.0.0.tgz#bbce07c9c529d9333d40db881fd4a1795dd84892" + integrity sha512-2z5Nafy1O0cTf69wKyNjGW/sNVMiqDnb4jgwfMG8ye8KnFJ5qmJpDccwIbJNhXIfbsxTg9SEec2oe1cexhMJvw== + +"@smithy/shared-ini-file-loader@^2.0.0", "@smithy/shared-ini-file-loader@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.1.tgz#47278552cf9462e731077da2f66a32d21b775e15" + integrity sha512-a463YiZrPGvM+F336rIF8pLfQsHAdCRAn/BiI/EWzg5xLoxbC7GSxIgliDDXrOu0z8gT3nhVsif85eU6jyct3A== + dependencies: + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/signature-v4@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-2.0.1.tgz#1f9e72930def3c25a3918ee7b562044fecbdaef4" + integrity sha512-jztv5Mirca42ilxmMDjzLdXcoAmRhZskGafGL49sRo5u7swEZcToEFrq6vtX5YMbSyTVrE9Teog5EFexY5Ff2Q== + dependencies: + "@smithy/eventstream-codec" "^2.0.1" + "@smithy/is-array-buffer" "^2.0.0" + "@smithy/types" "^2.0.2" + "@smithy/util-hex-encoding" "^2.0.0" + "@smithy/util-middleware" "^2.0.0" + "@smithy/util-uri-escape" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/smithy-client@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-2.0.1.tgz#34572ada6eccb62e6f0b38b6a9dc261e2cdf4d24" + integrity sha512-LHC5m6tYpEu1iNbONfvMbwtErboyTZJfEIPoD78Ei5MVr36vZQCaCla5mvo36+q/a2NAk2//fA5Rx3I1Kf7+lQ== + dependencies: + "@smithy/middleware-stack" "^2.0.0" + "@smithy/types" "^2.0.2" + "@smithy/util-stream" "^2.0.1" + tslib "^2.5.0" + +"@smithy/types@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.0.2.tgz#49d42724c909e845bfd80a2e195740614ce497f3" + integrity sha512-wcymEjIXQ9+NEfE5Yt5TInAqe1o4n+Nh+rh00AwoazppmUt8tdo6URhc5gkDcOYrcvlDVAZE7uG69nDpEGUKxw== + dependencies: + tslib "^2.5.0" + +"@smithy/url-parser@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-2.0.1.tgz#c0712fd7bde198644ffd57b202aa5d54bd437520" + integrity sha512-NpHVOAwddo+OyyIoujDL9zGL96piHWrTNXqltWmBvlUoWgt1HPyBuKs6oHjioyFnNZXUqveTOkEEq0U5w6Uv8A== + dependencies: + "@smithy/querystring-parser" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/util-base64@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-2.0.0.tgz#1beeabfb155471d1d41c8d0603be1351f883c444" + integrity sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA== + dependencies: + "@smithy/util-buffer-from" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-body-length-browser@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz#5447853003b4c73da3bc5f3c5e82c21d592d1650" + integrity sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg== + dependencies: + tslib "^2.5.0" + +"@smithy/util-body-length-node@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-2.0.0.tgz#4870b71cb9ded0123d984898ce952ce56896bc53" + integrity sha512-ZV7Z/WHTMxHJe/xL/56qZwSUcl63/5aaPAGjkfynJm4poILjdD4GmFI+V+YWabh2WJIjwTKZ5PNsuvPQKt93Mg== + dependencies: + tslib "^2.5.0" + +"@smithy/util-buffer-from@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz#7eb75d72288b6b3001bc5f75b48b711513091deb" + integrity sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw== + dependencies: + "@smithy/is-array-buffer" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-config-provider@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz#4dd6a793605559d94267312fd06d0f58784b4c38" + integrity sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg== + dependencies: + tslib "^2.5.0" + +"@smithy/util-defaults-mode-browser@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.1.tgz#650805fc2f308dee8efcf812392a6578ebcc652d" + integrity sha512-w72Qwsb+IaEYEFtYICn0Do42eFju78hTaBzzJfT107lFOPdbjWjKnFutV+6GL/nZd5HWXY7ccAKka++C3NrjHw== + dependencies: + "@smithy/property-provider" "^2.0.1" + "@smithy/types" "^2.0.2" + bowser "^2.11.0" + tslib "^2.5.0" + +"@smithy/util-defaults-mode-node@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.1.tgz#3a8fc607735481878c7c4c739da358bd0bb9bcae" + integrity sha512-dNF45caelEBambo0SgkzQ0v76m4YM+aFKZNTtSafy7P5dVF8TbjZuR2UX1A5gJABD9XK6lzN+v/9Yfzj/EDgGg== + dependencies: + "@smithy/config-resolver" "^2.0.1" + "@smithy/credential-provider-imds" "^2.0.1" + "@smithy/node-config-provider" "^2.0.1" + "@smithy/property-provider" "^2.0.1" + "@smithy/types" "^2.0.2" + tslib "^2.5.0" + +"@smithy/util-hex-encoding@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz#0aa3515acd2b005c6d55675e377080a7c513b59e" + integrity sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA== + dependencies: + tslib "^2.5.0" + +"@smithy/util-middleware@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-2.0.0.tgz#706681d4a1686544a2275f68266304233f372c99" + integrity sha512-eCWX4ECuDHn1wuyyDdGdUWnT4OGyIzV0LN1xRttBFMPI9Ff/4heSHVxneyiMtOB//zpXWCha1/SWHJOZstG7kA== + dependencies: + tslib "^2.5.0" + +"@smithy/util-retry@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-2.0.0.tgz#7ac5d5f12383a9d9b2a43f9ff25f3866c8727c24" + integrity sha512-/dvJ8afrElasuiiIttRJeoS2sy8YXpksQwiM/TcepqdRVp7u4ejd9C4IQURHNjlfPUT7Y6lCDSa2zQJbdHhVTg== + dependencies: + "@smithy/service-error-classification" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-stream@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-2.0.1.tgz#cbe2af5704a6050b9075835a8e7251185901864b" + integrity sha512-2a0IOtwIKC46EEo7E7cxDN8u2jwOiYYJqcFKA6rd5rdXqKakHT2Gc+AqHWngr0IEHUfW92zX12wRQKwyoqZf2Q== + dependencies: + "@smithy/fetch-http-handler" "^2.0.1" + "@smithy/node-http-handler" "^2.0.1" + "@smithy/types" "^2.0.2" + "@smithy/util-base64" "^2.0.0" + "@smithy/util-buffer-from" "^2.0.0" + "@smithy/util-hex-encoding" "^2.0.0" + "@smithy/util-utf8" "^2.0.0" + tslib "^2.5.0" + +"@smithy/util-uri-escape@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz#19955b1a0f517a87ae77ac729e0e411963dfda95" + integrity sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw== + dependencies: + tslib "^2.5.0" + +"@smithy/util-utf8@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.0.0.tgz#b4da87566ea7757435e153799df9da717262ad42" + integrity sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ== + dependencies: + "@smithy/util-buffer-from" "^2.0.0" + tslib "^2.5.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/babel__core@^7.1.14": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.1.tgz#916ecea274b0c776fec721e333e55762d3a9614b" + integrity sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.4" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.4.tgz#1f20ce4c5b1990b37900b63f050182d28c2439b7" + integrity sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.1" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.1.tgz#dd6f1d2411ae677dcb2db008c962598be31d6acf" + integrity sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg== + dependencies: + "@babel/types" "^7.20.7" + +"@types/bn.js@^5.1.0", "@types/bn.js@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.1.tgz#b51e1b55920a4ca26e9285ff79936bbdec910682" + integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== + dependencies: + "@types/node" "*" + +"@types/graceful-fs@^4.1.3": + version "4.1.6" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.6.tgz#e14b2576a1c25026b7f02ede1de3b84c3a1efeae" + integrity sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + +"@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.0.3": + version "29.5.3" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.3.tgz#7a35dc0044ffb8b56325c6802a4781a626b05777" + integrity sha512-1Nq7YrO/vJE/FYnqYyw0FS8LdrjExSgIiHyKg7xPpn+yi8Q4huZryKnkJatN1ZRH89Kw2v33/8ZMB7DuZeSLlA== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@^7.0.9": + version "7.0.12" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/node@*", "@types/node@>=13.7.0": + version "20.4.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.7.tgz#74d323a93f1391a63477b27b9aec56669c98b2ab" + integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g== + +"@types/node@^12.12.6": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/pbkdf2@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" + integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== + dependencies: + "@types/node" "*" + +"@types/secp256k1@^4.0.1": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" + integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== + dependencies: + "@types/node" "*" + +"@types/semver@^7.3.12": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.0.tgz#591c1ce3a702c45ee15f47a42ade72c2fd78978a" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + +"@types/stack-utils@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" + integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + +"@types/triple-beam@^1.3.2": + version "1.3.2" + resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.2.tgz#38ecb64f01aa0d02b7c8f4222d7c38af6316fef8" + integrity sha512-txGIh+0eDFzKGC25zORnswy+br1Ha7hj5cMVwKIU7+s0U2AxxJru/jZSMU6OC9MJWP6+pc/hc6ZjyZShpsyY2g== + +"@types/webidl-conversions@*": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.0.tgz#2b8e60e33906459219aa587e9d1a612ae994cfe7" + integrity sha512-xTE1E+YF4aWPJJeUzaZI5DRntlkY3+BCVJi0axFptnjGmAoWxkyREIh/XMrfxVLejwQxMCfDXdICo0VLxThrog== + +"@types/whatwg-url@^8.2.1": + version "8.2.2" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.2.tgz#749d5b3873e845897ada99be4448041d4cc39e63" + integrity sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA== + dependencies: + "@types/node" "*" + "@types/webidl-conversions" "*" + +"@types/yargs-parser@*": + version "21.0.0" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" + integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + +"@types/yargs@^17.0.8": + version "17.0.24" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.24.tgz#b3ef8d50ad4aa6aecf6ddc97c580a00f5aa11902" + integrity sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@^5.39.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz#aeef0328d172b9e37d9bab6dbc13b87ed88977db" + integrity sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/type-utils" "5.62.0" + "@typescript-eslint/utils" "5.62.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/scope-manager@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz#d9457ccc6a0b8d6b37d0eb252a23022478c5460c" + integrity sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + +"@typescript-eslint/type-utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz#286f0389c41681376cdad96b309cedd17d70346a" + integrity sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew== + dependencies: + "@typescript-eslint/typescript-estree" "5.62.0" + "@typescript-eslint/utils" "5.62.0" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.62.0.tgz#258607e60effa309f067608931c3df6fed41fd2f" + integrity sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ== + +"@typescript-eslint/typescript-estree@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz#7d17794b77fabcac615d6a48fb143330d962eb9b" + integrity sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA== + dependencies: + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/visitor-keys" "5.62.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.62.0.tgz#141e809c71636e4a75daa39faed2fb5f4b10df86" + integrity sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.62.0" + "@typescript-eslint/types" "5.62.0" + "@typescript-eslint/typescript-estree" "5.62.0" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.62.0": + version "5.62.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz#2174011917ce582875954ffe2f6912d5931e353e" + integrity sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw== + dependencies: + "@typescript-eslint/types" "5.62.0" + eslint-visitor-keys "^3.3.0" + +abortcontroller-polyfill@^1.7.3: + version "1.7.5" + resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" + integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1, acorn@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" + integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== + +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" + +ajv@^6.12.4: + 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" + +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-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-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== + +anymatch@^3.0.3, 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" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + 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" + +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== + +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== + +async@^3.2.3: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +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== + +available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + +axios@^1.3.6: + version "1.4.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.4.0.tgz#38a7bf1224cd308de271146038b551d725f0be1f" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +babel-jest@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.6.2.tgz#cada0a59e07f5acaeb11cbae7e3ba92aec9c1126" + integrity sha512-BYCzImLos6J3BH/+HvUCHG1dTf2MzmAB4jaVxHV+29RZLjR29XuYTmsf2sdDwkrb+FczkGo3kOhE7ga6sI0P4A== + dependencies: + "@jest/transform" "^29.6.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-plugin-polyfill-corejs2@^0.4.4: + version "0.4.5" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.5.tgz#8097b4cb4af5b64a1d11332b6fb72ef5e64a054c" + integrity sha512-19hwUH5FKl49JEsvyTcoHakh6BE0wgXLLptIyKZ3PijHc/Ci521wygORCUCCred+E/twuqRyAkE02BAWPmsHOg== + dependencies: + "@babel/compat-data" "^7.22.6" + "@babel/helper-define-polyfill-provider" "^0.4.2" + semver "^6.3.1" + +babel-plugin-polyfill-corejs3@^0.8.2: + version "0.8.3" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.3.tgz#b4f719d0ad9bb8e0c23e3e630c0c8ec6dd7a1c52" + integrity sha512-z41XaniZL26WLrvjy7soabMXrfPWARN25PZoriDEiLMxAp50AUW3t35BGQUMg5xK3UrpVTtagIDklxYa+MhiNA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.2" + core-js-compat "^3.31.0" + +babel-plugin-polyfill-regenerator@^0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz#80d0f3e1098c080c8b5a65f41e9427af692dc326" + integrity sha512-tAlOptU0Xj34V1Y2PNTL4Y0FOJMDB6bZmoW39FeCQIhigGLkqu3Fj6uiXpxIf6Ij274ENdYx64y6Au+ZKlb1IA== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.4.2" + +babel-plugin-transform-import-meta@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-import-meta/-/babel-plugin-transform-import-meta-2.2.1.tgz#eb5b79019ff0a9157b94d8280955121189a2964b" + integrity sha512-AxNh27Pcg8Kt112RGa3Vod2QS2YXKKJ6+nSvRtv7qQTJAdx0MZa4UHZ4lnxHUWA2MNbLuZQv5FVab4P1CoLOWw== + dependencies: + "@babel/template" "^7.4.4" + tslib "^2.4.0" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + +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== + +base-x@^3.0.2, base-x@^3.0.8: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +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== + +bignumber.js@^9.0.0: + version "9.1.1" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.1.1.tgz#c4df7dc496bd849d4c9464344c1aa74228b4dac6" + integrity sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bindings@^1.3.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.2.1.tgz#5057e4206eadb4a97f7c0b6e197a505042fc3814" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA== + +bn.js@^4.11.6, 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== + +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +bowser@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + +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" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +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== + +browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserslist@^4.21.9: + version "4.21.10" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.10.tgz#dbbac576628c13d3b2231332cb2ec5a46e015bb0" + integrity sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ== + dependencies: + caniuse-lite "^1.0.30001517" + electron-to-chromium "^1.4.477" + node-releases "^2.0.13" + update-browserslist-db "^1.0.11" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +bson@^4.7.2: + version "4.7.2" + resolved "https://registry.yarnpkg.com/bson/-/bson-4.7.2.tgz#320f4ad0eaf5312dd9b45dc369cc48945e2a5f2e" + integrity sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ== + dependencies: + buffer "^5.6.0" + +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-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + integrity sha512-3dthu5CYiVB1DEJp61FtApNnNndTckcqe4pFcLdvHtrpG+kcyekCJKg4MRiDcFW7A6AODnXB9U4dwQiCW5kzJQ== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^5.5.0, buffer@^5.6.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" + +bufferutil@^4.0.1: + version "4.0.7" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.7.tgz#60c0d19ba2c992dd8273d3f73772ffc894c153ad" + integrity sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw== + dependencies: + node-gyp-build "^4.3.0" + +call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +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== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001517: + version "1.0.30001519" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001519.tgz#3e7b8b8a7077e78b0eb054d69e6edf5c7df35601" + integrity sha512-0QHgqR+Jv4bxHMp8kZ1Kn8CH55OikjKJ6JmKkZYP1F3D7w+lnFXF70nG5eNfsZS89jadi5Ywy5UCSKLAglIRkg== + +chalk@^2.0.0: + 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" + +chalk@^4.0.0: + 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" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +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" + +ci-info@^3.2.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +cids@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" + integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.6.0" + multicodec "^1.0.0" + multihashes "~0.4.15" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +class-is@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" + integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== + +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" + +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== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +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: + 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" + +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@^9.0.0: + version "9.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30" + integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ== + +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== + +content-hash@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" + integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== + dependencies: + cids "^0.7.1" + multicodec "^0.5.5" + multihashes "^0.4.15" + +convert-source-map@^1.6.0, convert-source-map@^1.7.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== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +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== + +core-js-compat@^3.31.0: + version "3.32.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.0.tgz#f41574b6893ab15ddb0ac1693681bd56c8550a90" + integrity sha512-7a9a3D1k4UCVKnLhrgALyFcP7YCsLOQIxPd0dKjf/6GuPcgyiGP70ewWdCGrSK7evyhymi0qO4EqCmSJofDeYw== + dependencies: + browserslist "^4.21.9" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.2.tgz#3cad35a934b8bf71f25ca524b6da51fb7eace2ff" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-fetch@^3.1.4: + 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.2, 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" + +d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + +debug@4, debug@4.x, debug@^4.1.0, debug@^4.1.1, debug@^4.3.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: + 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" + +decode-uri-component@^0.2.0: + 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@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== + dependencies: + mimic-response "^1.0.0" + +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +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== + +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== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +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" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + +electron-to-chromium@^1.4.477: + version "1.4.484" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.484.tgz#770358eba089471c5dae5719db3a5a4fbf02bfb2" + integrity sha512-nO3ZEomTK2PO/3TUXgEx0A97xZTpKVf4p427lABHuCpT1IQ2N+njVh29DkQkCk6Q4m2wjU+faK4xAcfFndwjvw== + +elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + 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.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +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== + +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== + +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" + +es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.62" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.62.tgz#5e6adc19a6da524bf3d1e02bbc8960e5eb49a9a5" + integrity sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + +es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g== + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + +es6-promise@^4.2.8: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +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" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz#8c2095440eca8c933bedcadf16fefa44dbe9ba5f" + integrity sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw== + +eslint@^8.24.0: + version "8.46.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.46.0.tgz#a06a0ff6974e53e643acc42d1dcf2e7f797b3552" + integrity sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.1" + "@eslint/js" "^8.46.0" + "@humanwhocodes/config-array" "^0.11.10" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.2" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +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.1.0, 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== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eth-ens-namehash@2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + integrity sha512-VWEI1+KJfz4Km//dadyvBBoBeSQ0MHTXPvr8UIXiLW6IanxvAV+DmlZAijZwAyggqGUfwQBeHf7tc9wzc1piSw== + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + +eth-lib@0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + +ethereum-bloom-filters@^1.0.10, ethereum-bloom-filters@^1.0.6: + version "1.0.10" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" + integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== + dependencies: + js-sha3 "^0.8.0" + +ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + +ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.1, ethereumjs-util@^7.1.2, ethereumjs-util@^7.1.5: + version "7.1.5" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw== + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + +eventemitter3@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" + integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== + +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^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" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.6.2.tgz#7b08e83eba18ddc4a2cf62b5f2d1918f5cd84521" + integrity sha512-iAErsLxJ8C+S02QbLAwgSGSezLQK+XXRDt8IuFXFpwCNw2ECmzZSmjKcCaFVp5VRMk+WAvz6h6jokzEzBFZEuA== + dependencies: + "@jest/expect-utils" "^29.6.2" + "@types/node" "*" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + +ext@^1.1.2: + version "1.7.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.7.0.tgz#0ea4383c0103d60e70be99e9a7f11027a33c4f5f" + integrity sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw== + dependencies: + type "^2.7.2" + +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-glob@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + 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.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.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-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-xml-parser@4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz#a6747a09296a6cb34f2ae634019bf1738f3b421f" + integrity sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g== + dependencies: + strnum "^1.0.5" + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.15.0.tgz#d04d07c6a2a68fe4599fea8d2e103a937fae6b3a" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +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== + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.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" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +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: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +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" + +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" + +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@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +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-intrinsic@^1.0.2, get-intrinsic@^1.1.3: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz#d295644fed4505fc9cde952c37ee12b477a83d82" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +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-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +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-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + 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" + +global@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + +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== + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.0.4, globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +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" + +graceful-fs@^4.2.9: + 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== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +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-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, 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: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + 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" + +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" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + integrity sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg== + +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== + +idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== + dependencies: + punycode "2.1.0" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.2.1: + 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-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +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.1, inherits@^2.0.3, inherits@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ip@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" + integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== + +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-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-core-module@^2.11.0: + version "2.12.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== + dependencies: + has "^1.0.3" + +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-function@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +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@^4.0.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-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + +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-path-inside@^3.0.3: + 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-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-typed-array@^1.1.3: + version "1.1.12" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" + integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== + dependencies: + which-typed-array "^1.1.11" + +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== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + +istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== + dependencies: + execa "^5.0.0" + p-limit "^3.1.0" + +jest-circus@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.6.2.tgz#1e6ffca60151ac66cad63fce34f443f6b5bb4258" + integrity sha512-G9mN+KOYIUe2sB9kpJkO9Bk18J4dTDArNFPwoZ7WKHKel55eKIS/u2bLthxgojwlf9NLCVQfgzM/WsOVvoC6Fw== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/expect" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.6.2" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-runtime "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + p-limit "^3.1.0" + pretty-format "^29.6.2" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.6.2.tgz#edb381763398d1a292cd1b636a98bfa5644b8fda" + integrity sha512-TT6O247v6dCEX2UGHGyflMpxhnrL0DNqP2fRTKYm3nJJpCTfXX3GCMQPGFjXDoj0i5/Blp3jriKXFgdfmbYB6Q== + dependencies: + "@jest/core" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + prompts "^2.0.1" + yargs "^17.3.1" + +jest-config@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.6.2.tgz#c68723f06b31ca5e63030686e604727d406cd7c3" + integrity sha512-VxwFOC8gkiJbuodG9CPtMRjBUNZEHxwfQXmIudSTzFWxaci3Qub1ddTRbFNQlD/zUeaifLndh/eDccFX4wCMQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.6.2" + "@jest/types" "^29.6.1" + babel-jest "^29.6.2" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.6.2" + jest-environment-node "^29.6.2" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-runner "^29.6.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.6.2" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.6.2.tgz#c36001e5543e82a0805051d3ceac32e6825c1c46" + integrity sha512-t+ST7CB9GX5F2xKwhwCf0TAR17uNDiaPTZnVymP9lw0lssa9vG+AFyDZoeIHStU3WowFFwT+ky+er0WVl2yGhA== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.6.2.tgz#c9e4b340bcbe838c73adf46b76817b15712d02ce" + integrity sha512-MsrsqA0Ia99cIpABBc3izS1ZYoYfhIy0NNWqPSE0YXbQjwchyt6B1HD2khzyPe1WiJA7hbxXy77ZoUQxn8UlSw== + dependencies: + "@jest/types" "^29.6.1" + chalk "^4.0.0" + jest-get-type "^29.4.3" + jest-util "^29.6.2" + pretty-format "^29.6.2" + +jest-environment-node@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.6.2.tgz#a9ea2cabff39b08eca14ccb32c8ceb924c8bb1ad" + integrity sha512-YGdFeZ3T9a+/612c5mTQIllvWkddPbYcN2v95ZH24oWMbGA4GGS2XdIF92QMhUhvrjjuQWYgUGW2zawOyH63MQ== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-mock "^29.6.2" + jest-util "^29.6.2" + +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== + +jest-haste-map@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.6.2.tgz#298c25ea5255cfad8b723179d4295cf3a50a70d1" + integrity sha512-+51XleTDAAysvU8rT6AnS1ZJ+WHVNqhj1k6nTvN2PYP+HjU3kqlaKQ1Lnw3NYW3bm2r8vq82X0Z1nDDHZMzHVA== + dependencies: + "@jest/types" "^29.6.1" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.6.2" + jest-worker "^29.6.2" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.6.2.tgz#e2b307fee78cab091c37858a98c7e1d73cdf5b38" + integrity sha512-aNqYhfp5uYEO3tdWMb2bfWv6f0b4I0LOxVRpnRLAeque2uqOVVMLh6khnTcE2qJ5wAKop0HcreM1btoysD6bPQ== + dependencies: + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-matcher-utils@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.6.2.tgz#39de0be2baca7a64eacb27291f0bd834fea3a535" + integrity sha512-4LiAk3hSSobtomeIAzFTe+N8kL6z0JtF3n6I4fg29iIW7tt99R7ZcIFW34QkX+DuVrf+CUe6wuVOpm7ZKFJzZQ== + dependencies: + chalk "^4.0.0" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + pretty-format "^29.6.2" + +jest-message-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.6.2.tgz#af7adc2209c552f3f5ae31e77cf0a261f23dc2bb" + integrity sha512-vnIGYEjoPSuRqV8W9t+Wow95SDp6KPX2Uf7EoeG9G99J2OVh7OSwpS4B6J0NfpEIpfkBNHlBZpA2rblEuEFhZQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.6.2" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.6.2.tgz#ef9c9b4d38c34a2ad61010a021866dad41ce5e00" + integrity sha512-hoSv3lb3byzdKfwqCuT6uTscan471GUECqgNYykg6ob0yiAw3zYc7OrPnI9Qv8Wwoa4lC7AZ9hyS4AiIx5U2zg== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + jest-util "^29.6.2" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-resolve-dependencies@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.6.2.tgz#36435269b6672c256bcc85fb384872c134cc4cf2" + integrity sha512-LGqjDWxg2fuQQm7ypDxduLu/m4+4Lb4gczc13v51VMZbVP5tSBILqVx8qfWcsdP8f0G7aIqByIALDB0R93yL+w== + dependencies: + jest-regex-util "^29.4.3" + jest-snapshot "^29.6.2" + +jest-resolve@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.6.2.tgz#f18405fe4b50159b7b6d85e81f6a524d22afb838" + integrity sha512-G/iQUvZWI5e3SMFssc4ug4dH0aZiZpsDq9o1PtXTV1210Ztyb2+w+ZgQkB3iOiC5SmAEzJBOHWz6Hvrd+QnNPw== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-pnp-resolver "^1.2.2" + jest-util "^29.6.2" + jest-validate "^29.6.2" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.6.2.tgz#89e8e32a8fef24781a7c4c49cd1cb6358ac7fc01" + integrity sha512-wXOT/a0EspYgfMiYHxwGLPCZfC0c38MivAlb2lMEAlwHINKemrttu1uSbcGbfDV31sFaPWnWJPmb2qXM8pqZ4w== + dependencies: + "@jest/console" "^29.6.2" + "@jest/environment" "^29.6.2" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.4.3" + jest-environment-node "^29.6.2" + jest-haste-map "^29.6.2" + jest-leak-detector "^29.6.2" + jest-message-util "^29.6.2" + jest-resolve "^29.6.2" + jest-runtime "^29.6.2" + jest-util "^29.6.2" + jest-watcher "^29.6.2" + jest-worker "^29.6.2" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.6.2.tgz#692f25e387f982e89ab83270e684a9786248e545" + integrity sha512-2X9dqK768KufGJyIeLmIzToDmsN0m7Iek8QNxRSI/2+iPFYHF0jTwlO3ftn7gdKd98G/VQw9XJCk77rbTGZnJg== + dependencies: + "@jest/environment" "^29.6.2" + "@jest/fake-timers" "^29.6.2" + "@jest/globals" "^29.6.2" + "@jest/source-map" "^29.6.0" + "@jest/test-result" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.6.2" + jest-message-util "^29.6.2" + jest-mock "^29.6.2" + jest-regex-util "^29.4.3" + jest-resolve "^29.6.2" + jest-snapshot "^29.6.2" + jest-util "^29.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.6.2.tgz#9b431b561a83f2bdfe041e1cab8a6becdb01af9c" + integrity sha512-1OdjqvqmRdGNvWXr/YZHuyhh5DeaLp1p/F8Tht/MrMw4Kr1Uu/j4lRG+iKl1DAqUJDWxtQBMk41Lnf/JETYBRA== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.6.2" + "@jest/transform" "^29.6.2" + "@jest/types" "^29.6.1" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.6.2" + graceful-fs "^4.2.9" + jest-diff "^29.6.2" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.6.2" + jest-message-util "^29.6.2" + jest-util "^29.6.2" + natural-compare "^1.4.0" + pretty-format "^29.6.2" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.6.2.tgz#8a052df8fff2eebe446769fd88814521a517664d" + integrity sha512-3eX1qb6L88lJNCFlEADKOkjpXJQyZRiavX1INZ4tRnrBVr2COd3RgcTLyUiEXMNBlDU/cgYq6taUS0fExrWW4w== + dependencies: + "@jest/types" "^29.6.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.6.2.tgz#25d972af35b2415b83b1373baf1a47bb266c1082" + integrity sha512-vGz0yMN5fUFRRbpJDPwxMpgSXW1LDKROHfBopAvDcmD6s+B/s8WJrwi+4bfH4SdInBA5C3P3BI19dBtKzx1Arg== + dependencies: + "@jest/types" "^29.6.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.4.3" + leven "^3.1.0" + pretty-format "^29.6.2" + +jest-watcher@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.6.2.tgz#77c224674f0620d9f6643c4cfca186d8893ca088" + integrity sha512-GZitlqkMkhkefjfN/p3SJjrDaxPflqxEAv3/ik10OirZqJGYH5rPiIsgVcfof0Tdqg3shQGdEIxDBx+B4tuLzA== + dependencies: + "@jest/test-result" "^29.6.2" + "@jest/types" "^29.6.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.6.2" + string-length "^4.0.1" + +jest-worker@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.6.2.tgz#682fbc4b6856ad0aa122a5403c6d048b83f3fb44" + integrity sha512-l3ccBOabTdkng8I/ORCkADz4eSMKejTYv1vB/Z83UiubqhC1oQ5Li6dWCyqOIvSifGjUBxuvxvlm6KGK2DtuAQ== + dependencies: + "@types/node" "*" + jest-util "^29.6.2" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.0.3: + version "29.6.2" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.6.2.tgz#3bd55b9fd46a161b2edbdf5f1d1bd0d1eab76c42" + integrity sha512-8eQg2mqFbaP7CwfsTpCxQ+sHzw1WuNWL5UUvjnWP4hx2riGz9fPSzYOaU5q8/GqWn1TfgZIVTqYJygbGbWAANg== + dependencies: + "@jest/core" "^29.6.2" + "@jest/types" "^29.6.1" + import-local "^3.0.2" + jest-cli "^29.6.2" + +js-sha3@0.8.0, 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-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + integrity sha512-GII20kjaPX0zJ8wzkTbNDYMY7msuZcTWk8S5UOh6806Jq/wz1J8/bnr8uGU0DAUmYDjj2Mr4X1cW8v/GLYnR+g== + +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-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +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== + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== + +json-parse-even-better-errors@^2.3.0: + 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-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +kareem@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.5.1.tgz#7b8203e11819a8e77a34b3517d3ead206764d15d" + integrity sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA== + +keccak@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.3.tgz#4bc35ad917be1ef54ff246f904c2bbbf9ac61276" + integrity sha512-JZrLIAJWuZxKbCilMpNz5Vj7Vtb4scDG3dMXLOsbzBmQGyjwE61BbW7bJkfKKCShXiQZt3T6sBgALRtmd+nZaQ== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + +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== + +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kuler/-/kuler-2.0.0.tgz#e2c570a3800388fb44407e851531c1d670b061b3" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +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== + +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.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +logform@^2.3.2, logform@^2.4.0: + version "2.5.1" + resolved "https://registry.yarnpkg.com/logform/-/logform-2.5.1.tgz#44c77c34becd71b3a42a3970c77929e52c6ed48b" + integrity sha512-9FyqAm9o9NKKfiAKfZoYo9bGXXuwMkxQiQttkT4YjjVtQVIQtK6LmVtlxmCaFswo6N4AfEkHqZTV0taDtPotNg== + dependencies: + "@colors/colors" "1.5.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@^5.0.0, long@^5.2.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +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_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== + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + +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.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== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + 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.12: + 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@^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-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== + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ== + dependencies: + dom-walk "^0.1.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@^3.0.4, minimatch@^3.0.5, 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" + +mongodb-connection-string-url@^2.5.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz#57901bf352372abdde812c81be47b75c6b2ec5cf" + integrity sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ== + dependencies: + "@types/whatwg-url" "^8.2.1" + whatwg-url "^11.0.0" + +mongodb@4.16.0: + version "4.16.0" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.16.0.tgz#8b0043de7b577c6a7e0ce44a2ca7315b9c0a7927" + integrity sha512-0EB113Fsucaq1wsY0dOhi1fmZOwFtLOtteQkiqOXGklvWMnSH3g2QS53f0KTP+/6qOkuoXE2JksubSZNmxeI+g== + dependencies: + bson "^4.7.2" + mongodb-connection-string-url "^2.5.4" + socks "^2.7.1" + optionalDependencies: + "@aws-sdk/credential-providers" "^3.186.0" + saslprep "^1.0.3" + +mongoose@^6.5.2: + version "6.11.5" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-6.11.5.tgz#caac6406698af9802a3832ce676cf151742ae380" + integrity sha512-ZarPe1rCHG4aVb78xLuok4BBIm0HMz/Y/CjxYXCk3Qz1mEhS7bPMy6ZhSX2/Dng//R7ei8719j6K87UVM/1b3g== + dependencies: + bson "^4.7.2" + kareem "2.5.1" + mongodb "4.16.0" + mpath "0.9.0" + mquery "4.0.3" + ms "2.1.3" + sift "16.0.1" + +mpath@0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.9.0.tgz#0c122fe107846e31fc58c75b09c35514b3871904" + integrity sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew== + +mquery@4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-4.0.3.tgz#4d15f938e6247d773a942c912d9748bd1965f89d" + integrity sha512-J5heI+P08I6VJ2Ky3+33IpCdAvlYGTSUjwTPxkAr8i8EoduPMBX2OY/wa3IKZIQl7MU4SbFk8ndgSKyB/cl1zA== + dependencies: + debug "4.x" + +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.3, 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== + +multibase@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multibase@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" + integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + +multicodec@^0.5.5: + version "0.5.7" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" + integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== + dependencies: + varint "^5.0.0" + +multicodec@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" + integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== + dependencies: + buffer "^5.6.0" + varint "^5.0.0" + +multihashes@^0.4.15, multihashes@~0.4.15: + version "0.4.21" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" + integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + +mylas@^2.1.9: + version "2.1.13" + resolved "https://registry.yarnpkg.com/mylas/-/mylas-2.1.13.tgz#1e23b37d58fdcc76e15d8a5ed23f9ae9fc0cbdf4" + integrity sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg== + +nan@^2.17.0: + version "2.17.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb" + integrity sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + +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-fetch@^2.6.12: + version "2.6.12" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.12.tgz#02eb8e22074018e3d5a83016649d04df0e348fba" + integrity sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.6.0.tgz#0c52e4cbf54bbd28b709820ef7b6a3c2d6209055" + integrity sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-rdkafka@^2.13.0: + version "2.17.0" + resolved "https://registry.yarnpkg.com/node-rdkafka/-/node-rdkafka-2.17.0.tgz#d0fe79165098d6fcacdfb0570abe2adf861a515b" + integrity sha512-vFABzRcE5FaH0WqfqJRxDoqeG6P8UEB3M4qFQ7SkwMgQueMMO78+fm8MYfl5hLW3bBYfBekK2BXIIr0lDQtSEQ== + dependencies: + bindings "^1.3.1" + nan "^2.17.0" + +node-releases@^2.0.13: + version "2.0.13" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" + integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== + +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== + +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" + +number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig== + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + +object-assign@^4.1.0, 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== + +oboe@2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.5.tgz#5554284c543a2266d7a38f17e073821fbde393cd" + integrity sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA== + dependencies: + http-https "^1.0.0" + +once@^1.3.0, once@^1.3.1: + 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@^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" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.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, p-limit@^3.1.0: + 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-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-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== + +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-headers@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" + integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== + +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" + +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.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-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-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== + +pbkdf2@^3.0.17: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +plimit-lit@^1.2.6: + version "1.5.0" + resolved "https://registry.yarnpkg.com/plimit-lit/-/plimit-lit-1.5.0.tgz#f66df8a7041de1e965c4f1c0697ab486968a92a5" + integrity sha512-Eb/MqCb1Iv/ok4m1FqIXqvUKPISufcjZ605hl3KM/n8GaX8zfhtgdLwZU3vKjuHGh2O9Rjog/bHTq8ofIShdng== + dependencies: + queue-lit "^1.5.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +pretty-format@^29.0.0, pretty-format@^29.6.2: + version "29.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.6.2.tgz#3d5829261a8a4d89d8b9769064b29c50ed486a47" + integrity sha512-1q0oC8eRveTg5nnBEWMXAU2qpv65Gnuf2eCQzSjxpWFkPaPARwqZZDGuNE0zPAZfTCHzIk3A8dIjwlQKKLphyg== + dependencies: + "@jest/schemas" "^29.6.0" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +prompts@^2.0.1: + 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" + +protobufjs@^7.0.0: + version "7.2.4" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.2.4.tgz#3fc1ec0cdc89dd91aef9ba6037ba07408485c3ae" + integrity sha512-AT+RJgD2sH8phPmCf7OUZR8xGdcJRga4+1cOaXJ64hvcSkVhNcRHOwIxUatPH15+nj59WAGTDv3LSGZPEQbJaQ== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +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== + +punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + integrity sha512-Yxz2kRwT90aPiWEMHVYnEf4+rhwF1tBmmZ4KepCP+Wkium9JxtWnUm1nqGwpiAHr/tnTSeHqr3wb++jgSkXjhA== + +punycode@^2.1.0, punycode@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + +query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +queue-lit@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/queue-lit/-/queue-lit-1.5.0.tgz#8197fdafda1edd615c8a0fc14c48353626e5160a" + integrity sha512-IslToJ4eiCEE9xwMzq3viOO5nH8sUWUCwoElrhNMozzr9IIt2qqvB4I+uHu/zJTQVqc9R5DFwok4ijNK1pU3fA== + +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== + +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" + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +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" + +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" + +regenerate-unicode-properties@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" + integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + dependencies: + regenerate "^1.4.2" + +regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + +regenerator-transform@^0.15.1: + version "0.15.1" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.1.tgz#f6c4e99fc1b4591f780db2586328e4d9a9d8dc56" + integrity sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg== + dependencies: + "@babel/runtime" "^7.8.4" + +regexpu-core@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" + integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== + dependencies: + "@babel/regjsgen" "^0.8.0" + regenerate "^1.4.2" + regenerate-unicode-properties "^10.1.0" + regjsparser "^0.9.1" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.1.0" + +regjsparser@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.9.1.tgz#272d05aa10c7c1f67095b1ff0addae8442fc5709" + integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== + dependencies: + jsesc "~0.5.0" + +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== + +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-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-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.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.14.2, resolve@^1.20.0: + version "1.22.2" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +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: + 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" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.2.4: + version "2.2.7" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + +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.5.6: + 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" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.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-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== + +saslprep@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + +scrypt-js@^3.0.0, scrypt-js@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +secp256k1@^4.0.1: + 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@^6.3.0, semver@^6.3.1: + 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.7, semver@^7.5.3: + 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" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +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== + +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== + +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== + +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@^2.7.0: + version "2.8.2" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" + integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== + dependencies: + decompress-response "^3.3.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" + +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== + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +socks@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.7.1.tgz#d8e651247178fde79c0663043e07240196857d55" + integrity sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ== + dependencies: + ip "^2.0.0" + smart-buffer "^4.2.0" + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +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== + +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ== + dependencies: + memory-pager "^1.0.2" + +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== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha512-R3f198pcvnB+5IpnBlRkphuE9n46WyVl8I39W/ZUTZLz4nqSP/oLYUrcnJrw462Ds8he4YKMov2efsTIw1BDGQ== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, 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_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" + +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-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +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-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strnum@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" + integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== + +supports-color@^5.3.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: + 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== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.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== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha512-G7r3AhovYtr5YKOWQkta8RKAPb+J9IsO4uVmzjl8AZwfhs8UcUwTiD6gcJYSgOtzyjvQKrKYn41syHbUWMkafA== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +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-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" + +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +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== + +ts-jest@^29.0.3: + version "29.1.1" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + +ts-node@^10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsc-alias@^1.8.7: + version "1.8.7" + resolved "https://registry.yarnpkg.com/tsc-alias/-/tsc-alias-1.8.7.tgz#4f8721b031a31345fa9f1fa8d3cf209d925abb88" + integrity sha512-59Q/zUQa3miTf99mLbSqaW0hi1jt4WoG8Uhe5hSZJHQpSoFW9eEwvW7jlKMHXWvT+zrzy3SN9PE/YBhQ+WVydA== + dependencies: + chokidar "^3.5.3" + commander "^9.0.0" + globby "^11.0.4" + mylas "^2.1.9" + normalize-path "^3.0.0" + plimit-lit "^1.2.6" + +tslib@^1.11.1, tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.1.0, tslib@^2.3.1, tslib@^2.4.0, "tslib@^2.4.1 || ^1.9.3", tslib@^2.5.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.1.tgz#fd8c9a0ff42590b25703c0acb3de3d3f4ede0410" + integrity sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +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@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + +type@^2.7.2: + version "2.7.2" + resolved "https://registry.yarnpkg.com/type/-/type-2.7.2.tgz#2376a15a3a28b1efa0f5350dcf72d24df6ef98d0" + integrity sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw== + +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@^4.9.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + +unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + +unicode-match-property-value-ecmascript@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz#cb5fffdcd16a05124f5a4b0bf7c3770208acbbe0" + integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + +unicode-property-aliases-ecmascript@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" + integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + 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" + +url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + integrity sha512-3AChu4NiXquPfeckE5R5cGdiHCMWJx1dwCWOmWIL4KHAziJNOFIYJlpGFeKDvwLPHovZRCxK3cYlwzqI9Vp+Gg== + +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +utf8@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + +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.5: + 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" + +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== + +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.1.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz#1b83ed4e397f58c85c266a570fc2558b5feb9265" + integrity sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + +varint@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" + integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +web3-core-helpers@1.10.0, web3-core-helpers@^1.8.2: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.10.0.tgz#1016534c51a5df77ed4f94d1fcce31de4af37fad" + integrity sha512-pIxAzFDS5vnbXvfvLSpaA1tfRykAe9adw43YCKsEYQwH0gCLL0kMLkaCX3q+Q8EVmAh+e1jWL/nl9U0de1+++g== + dependencies: + web3-eth-iban "1.10.0" + web3-utils "1.10.0" + +web3-core-method@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.10.0.tgz#82668197fa086e8cc8066742e35a9d72535e3412" + integrity sha512-4R700jTLAMKDMhQ+nsVfIXvH6IGJlJzGisIfMKWAIswH31h5AZz7uDUW2YctI+HrYd+5uOAlS4OJeeT9bIpvkA== + dependencies: + "@ethersproject/transactions" "^5.6.2" + web3-core-helpers "1.10.0" + web3-core-promievent "1.10.0" + web3-core-subscriptions "1.10.0" + web3-utils "1.10.0" + +web3-core-promievent@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.10.0.tgz#cbb5b3a76b888df45ed3a8d4d8d4f54ccb66a37b" + integrity sha512-68N7k5LWL5R38xRaKFrTFT2pm2jBNFaM4GioS00YjAKXRQ3KjmhijOMG3TICz6Aa5+6GDWYelDNx21YAeZ4YTg== + dependencies: + eventemitter3 "4.0.4" + +web3-core-requestmanager@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.10.0.tgz#4b34f6e05837e67c70ff6f6993652afc0d54c340" + integrity sha512-3z/JKE++Os62APml4dvBM+GAuId4h3L9ckUrj7ebEtS2AR0ixyQPbrBodgL91Sv7j7cQ3Y+hllaluqjguxvSaQ== + dependencies: + util "^0.12.5" + web3-core-helpers "1.10.0" + web3-providers-http "1.10.0" + web3-providers-ipc "1.10.0" + web3-providers-ws "1.10.0" + +web3-core-subscriptions@1.10.0, web3-core-subscriptions@^1.7.5: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.10.0.tgz#b534592ee1611788fc0cb0b95963b9b9b6eacb7c" + integrity sha512-HGm1PbDqsxejI075gxBc5OSkwymilRWZufIy9zEpnWKNmfbuv5FfHgW1/chtJP6aP3Uq2vHkvTDl3smQBb8l+g== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.0" + +web3-core@1.10.0, web3-core@^1.7.5: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.10.0.tgz#9aa07c5deb478cf356c5d3b5b35afafa5fa8e633" + integrity sha512-fWySwqy2hn3TL89w5TM8wXF1Z2Q6frQTKHWmP0ppRQorEK8NcHJRfeMiv/mQlSKoTS1F6n/nv2uyZsixFycjYQ== + dependencies: + "@types/bn.js" "^5.1.1" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-core-requestmanager "1.10.0" + web3-utils "1.10.0" + +web3-eth-abi@1.10.0, web3-eth-abi@^1.8.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.10.0.tgz#53a7a2c95a571e205e27fd9e664df4919483cce1" + integrity sha512-cwS+qRBWpJ43aI9L3JS88QYPfFcSJJ3XapxOQ4j40v6mk7ATpA8CVK1vGTzpihNlOfMVRBkR95oAj7oL6aiDOg== + dependencies: + "@ethersproject/abi" "^5.6.3" + web3-utils "1.10.0" + +web3-eth-accounts@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.10.0.tgz#2942beca0a4291455f32cf09de10457a19a48117" + integrity sha512-wiq39Uc3mOI8rw24wE2n15hboLE0E9BsQLdlmsL4Zua9diDS6B5abXG0XhFcoNsXIGMWXVZz4TOq3u4EdpXF/Q== + dependencies: + "@ethereumjs/common" "2.5.0" + "@ethereumjs/tx" "3.3.2" + eth-lib "0.2.8" + ethereumjs-util "^7.1.5" + scrypt-js "^3.0.1" + uuid "^9.0.0" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-utils "1.10.0" + +web3-eth-contract@1.10.0, web3-eth-contract@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.10.0.tgz#8e68c7654576773ec3c91903f08e49d0242c503a" + integrity sha512-MIC5FOzP/+2evDksQQ/dpcXhSqa/2hFNytdl/x61IeWxhh6vlFeSjq0YVTAyIzdjwnL7nEmZpjfI6y6/Ufhy7w== + dependencies: + "@types/bn.js" "^5.1.1" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-core-promievent "1.10.0" + web3-core-subscriptions "1.10.0" + web3-eth-abi "1.10.0" + web3-utils "1.10.0" + +web3-eth-ens@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.10.0.tgz#96a676524e0b580c87913f557a13ed810cf91cd9" + integrity sha512-3hpGgzX3qjgxNAmqdrC2YUQMTfnZbs4GeLEmy8aCWziVwogbuqQZ+Gzdfrym45eOZodk+lmXyLuAdqkNlvkc1g== + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-promievent "1.10.0" + web3-eth-abi "1.10.0" + web3-eth-contract "1.10.0" + web3-utils "1.10.0" + +web3-eth-iban@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.10.0.tgz#5a46646401965b0f09a4f58e7248c8a8cd22538a" + integrity sha512-0l+SP3IGhInw7Q20LY3IVafYEuufo4Dn75jAHT7c2aDJsIolvf2Lc6ugHkBajlwUneGfbRQs/ccYPQ9JeMUbrg== + dependencies: + bn.js "^5.2.1" + web3-utils "1.10.0" + +web3-eth-personal@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.10.0.tgz#94d525f7a29050a0c2a12032df150ac5ea633071" + integrity sha512-anseKn98w/d703eWq52uNuZi7GhQeVjTC5/svrBWEKob0WZ5kPdo+EZoFN0sp5a5ubbrk/E0xSl1/M5yORMtpg== + dependencies: + "@types/node" "^12.12.6" + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-net "1.10.0" + web3-utils "1.10.0" + +web3-eth@^1.8.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.10.0.tgz#38b905e2759697c9624ab080cfcf4e6c60b3a6cf" + integrity sha512-Z5vT6slNMLPKuwRyKGbqeGYC87OAy8bOblaqRTgg94CXcn/mmqU7iPIlG4506YdcdK3x6cfEDG7B6w+jRxypKA== + dependencies: + web3-core "1.10.0" + web3-core-helpers "1.10.0" + web3-core-method "1.10.0" + web3-core-subscriptions "1.10.0" + web3-eth-abi "1.10.0" + web3-eth-accounts "1.10.0" + web3-eth-contract "1.10.0" + web3-eth-ens "1.10.0" + web3-eth-iban "1.10.0" + web3-eth-personal "1.10.0" + web3-net "1.10.0" + web3-utils "1.10.0" + +web3-net@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.10.0.tgz#be53e7f5dafd55e7c9013d49c505448b92c9c97b" + integrity sha512-NLH/N3IshYWASpxk4/18Ge6n60GEvWBVeM8inx2dmZJVmRI6SJIlUxbL8jySgiTn3MMZlhbdvrGo8fpUW7a1GA== + dependencies: + web3-core "1.10.0" + web3-core-method "1.10.0" + web3-utils "1.10.0" + +web3-providers-http@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.10.0.tgz#864fa48675e7918c9a4374e5f664b32c09d0151b" + integrity sha512-eNr965YB8a9mLiNrkjAWNAPXgmQWfpBfkkn7tpEFlghfww0u3I0tktMZiaToJVcL2+Xq+81cxbkpeWJ5XQDwOA== + dependencies: + abortcontroller-polyfill "^1.7.3" + cross-fetch "^3.1.4" + es6-promise "^4.2.8" + web3-core-helpers "1.10.0" + +web3-providers-ipc@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.10.0.tgz#9747c7a6aee96a51488e32fa7c636c3460b39889" + integrity sha512-OfXG1aWN8L1OUqppshzq8YISkWrYHaATW9H8eh0p89TlWMc1KZOL9vttBuaBEi96D/n0eYDn2trzt22bqHWfXA== + dependencies: + oboe "2.1.5" + web3-core-helpers "1.10.0" + +web3-providers-ws@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.10.0.tgz#cb0b87b94c4df965cdf486af3a8cd26daf3975e5" + integrity sha512-sK0fNcglW36yD5xjnjtSGBnEtf59cbw4vZzJ+CmOWIKGIR96mP5l684g0WD0Eo+f4NQc2anWWXG74lRc9OVMCQ== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.10.0" + websocket "^1.0.32" + +web3-utils@1.10.0, web3-utils@^1.8.2: + version "1.10.0" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.10.0.tgz#ca4c1b431a765c14ac7f773e92e0fd9377ccf578" + integrity sha512-kSaCM0uMcZTNUSmn5vMEhlo02RObGNRRCkdX0V9UTAU0+lrvn0HSaudyCo6CQzuXUsnuY2ERJGCGPfeWmv19Rg== + dependencies: + bn.js "^5.2.1" + ethereum-bloom-filters "^1.0.6" + ethereumjs-util "^7.1.0" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.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== + +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + +websocket@^1.0.32: + version "1.0.34" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" + integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + +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.11, which-typed-array@^1.1.2: + version "1.1.11" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" + integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.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" + +winston-transport-sentry-node@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/winston-transport-sentry-node/-/winston-transport-sentry-node-2.7.0.tgz#cc591ebbe473099b64a9b188e7a8e9462424aaf0" + integrity sha512-WoqEM6nNP2U10JyPEI5tglVEu5WBa0LA9692xTmLZeVADlwTB1rZPJh0/J5oEeMPTIDVeD6sfKbssby+sCmmxg== + dependencies: + "@sentry/node" "^7.1.1" + triple-beam "^1.3.0" + tslib "^2.3.1" + winston "^3.3.3" + winston-transport "^4.4.0" + +winston-transport@^4.4.0, winston-transport@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/winston-transport/-/winston-transport-4.5.0.tgz#6e7b0dd04d393171ed5e4e4905db265f7ab384fa" + integrity sha512-YpZzcUzBedhlTAfJg6vJDlyEai/IFMIVcaEZZyl3UXIl4gmqRpU7AE89AHLkbzLUsv0NVmw7ts+iztqKxxPW1Q== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@^3.3.3, winston@^3.8.2: + 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" + +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" + +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@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +xhr-request-promise@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" + integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== + dependencies: + xhr-request "^1.1.0" + +xhr-request@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + +xhr@^2.0.4: + version "2.6.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" + integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== + dependencies: + global "~4.4.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + +xtend@^4.0.0: + 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== + +yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +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== + +yargs-parser@^21.0.1, 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@^17.3.1: + 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" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +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==