diff --git a/.env.http.example b/.env.http.example index a7b8cd7f0a..a1e835b6e5 100644 --- a/.env.http.example +++ b/.env.http.example @@ -62,6 +62,11 @@ OPERATOR_KEY_MAIN= # Operator private key used to sign transaction # ========== TRANSACTION POOL ======== # PENDING_TRANSACTION_STORAGE_TTL=30 # Time-to-live (TTL) in seconds for transaction payloads stored in Redis +# ========== LOCK SERVICE =========== +# LOCK_MAX_HOLD_MS=30000 # Maximum time in milliseconds a lock can be held before automatic force-release +# LOCAL_LOCK_MAX_ENTRIES=1000 # Maximum number of lock entries stored in memory +# LOCK_QUEUE_POLL_INTERVAL_MS=50 # Interval in milliseconds between queue position checks when waiting for a lock + # ========== HBAR RATE LIMITING ========== # HBAR_RATE_LIMIT_TINYBAR=25000000000 # Total HBAR budget (250 HBARs) # HBAR_RATE_LIMIT_DURATION=86400000 # HBAR budget limit duration (1 day) diff --git a/.env.ws.example b/.env.ws.example index c3359b67af..14f48fe413 100644 --- a/.env.ws.example +++ b/.env.ws.example @@ -59,6 +59,11 @@ SUBSCRIPTIONS_ENABLED=true # Must be true for the WebSocket server to func # ========== TRANSACTION POOL ======== # PENDING_TRANSACTION_STORAGE_TTL=30 # Time-to-live (TTL) in seconds for transaction payloads stored in Redis +# ========== LOCK SERVICE =========== +# LOCK_MAX_HOLD_MS=30000 # Maximum time in milliseconds a lock can be held before automatic force-release +# LOCAL_LOCK_MAX_ENTRIES=1000 # Maximum number of lock entries stored in memory +# LOCK_QUEUE_POLL_INTERVAL_MS=50 # Interval in milliseconds between queue position checks when waiting for a lock + # ========== OTHER SETTINGS ========== # CLIENT_TRANSPORT_SECURITY=false # Enable or disable TLS for both networks # USE_ASYNC_TX_PROCESSING=true # If true, returns tx hash immediately after prechecks diff --git a/charts/hedera-json-rpc-relay/values.yaml b/charts/hedera-json-rpc-relay/values.yaml index e0bc043ae3..63c68539b0 100644 --- a/charts/hedera-json-rpc-relay/values.yaml +++ b/charts/hedera-json-rpc-relay/values.yaml @@ -123,6 +123,11 @@ config: # REDIS_RECONNECT_DELAY_MS: # MULTI_SET: + # ========== LOCK SERVICE CONFIGURATION ========== + # LOCK_MAX_HOLD_MS: + # LOCAL_LOCK_MAX_ENTRIES: + # LOCK_QUEUE_POLL_INTERVAL_MS: + # ========== DEVELOPMENT & TESTING ========== # LOG_LEVEL: 'trace' diff --git a/docs/configuration.md b/docs/configuration.md index 9744f2a6ea..6d701eea4a 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -68,6 +68,7 @@ Unless you need to set a non-default value, it is recommended to only populate o | `IP_RATE_LIMIT_STORE` | null | Specifies the rate limit store to use for IP-based rate limiting: valid values are "LRU", "REDIS", with the possibility to be extended with a custom implementation (see [Store Selection](rate-limiting.md#store-selection)). If unset, falls back to Redis when `REDIS_ENABLED=true`, otherwise uses in-memory LRU. | | `JUMBO_TX_ENABLED` | "true" | Controls how large transactions are handled during `eth_sendRawTransaction`. When set to `true`, transactions up to 128KB can be sent directly to consensus nodes without using Hedera File Service (HFS), as long as contract bytecode doesn't exceed 24KB. When set to `false`, all transactions containing contract deployments use the traditional HFS approach. This feature leverages the increased transaction size limit to simplify processing of standard Ethereum transactions. | | `LIMIT_DURATION` | "60000" | The maximum duration in ms applied to IP-method based rate limits. | +| `LOCAL_LOCK_MAX_ENTRIES` | "1000" | Maximum number of lock entries stored in memory. Prevents unbounded memory growth. | | `MAX_GAS_ALLOWANCE_HBAR` | "0" | The maximum amount, in hbars, that the JSON-RPC Relay is willing to pay to complete the transaction in case the senders don't provide enough funds. Please note, in case of fully subsidized transactions, the sender must set the gas price to `0` and the JSON-RPC Relay must configure the `MAX_GAS_ALLOWANCE_HBAR` parameter high enough to cover the entire transaction cost. | | `MAX_TRANSACTION_FEE_THRESHOLD` | "15000000" | Used to set the max transaction fee. This is the HAPI fee which is paid by the relay operator account. | | `MIRROR_NODE_AGENT_CACHEABLE_DNS` | "true" | Flag to set if the mirror node agent should cacheable DNS lookups, using better-lookup library. | @@ -105,6 +106,8 @@ Unless you need to set a non-default value, it is recommended to only populate o | `TX_DEFAULT_GAS` | "400000" | Default gas for transactions that do not specify gas. | | `TXPOOL_API_ENABLED` | "false" | Enables all txpool related methods. | | `USE_ASYNC_TX_PROCESSING` | "true" | Set to `true` to enable `eth_sendRawTransaction` to return the transaction hash immediately after passing all prechecks, while processing the transaction asynchronously in the background. | +| `LOCK_MAX_HOLD_MS` | "30000" | Maximum time in milliseconds a lock can be held before automatic force-release. This TTL prevents deadlocks when transaction processing hangs or crashes. Default is 30 seconds. | +| `LOCK_QUEUE_POLL_INTERVAL_MS` | "50" | Interval in milliseconds between queue position checks when waiting for a lock. Lower values provide faster lock acquisition but increase Redis load. Default is 50ms. | | `USE_MIRROR_NODE_MODULARIZED_SERVICES` | null | Controls routing of Mirror Node traffic through modularized services. When set to `true`, enables routing a percentage of traffic to modularized services. When set to `false`, ensures traffic follows the traditional non-modularized flow. When not set (i.e. `null` by default), no specific routing preference is applied. As Mirror Node gradually transitions to a fully modularized architecture across all networks, this setting will eventually default to `true`. | ## Server diff --git a/docs/nonce-ordering-with-locks.md b/docs/nonce-ordering-with-locks.md new file mode 100644 index 0000000000..30de6d30ea --- /dev/null +++ b/docs/nonce-ordering-with-locks.md @@ -0,0 +1,314 @@ +> [!NOTE] +> This is an experimental feature hidden behind a flag `ENABLE_NONCE_ORDERING` + +## Nonce ordering with locks + +This document explains how per-sender address locking ensures transaction ordering and prevents nonce-related failures when multiple transactions from the same sender arrive in rapid succession. + +It covers the background and motivation, configuration, locking strategies, request flows, failure handling, and how this impacts `eth_sendRawTransaction`. + +--- + +### Background and motivation + +The Hedera JSON-RPC Relay processes `eth_sendRawTransaction` requests asynchronously. When multiple transactions from the same sender arrive within milliseconds of each other, asynchronous operations can cause them to reach consensus nodes out of order: + +``` +User submits: Tx(nonce=0) → Tx(nonce=1) → Tx(nonce=2) + ↓ ↓ ↓ +Async processing: [validate] [validate] [validate] + ↓ ↓ ↓ +Reaches consensus: Tx(nonce=1) ← Tx(nonce=0) ← Tx(nonce=2) ❌ Wrong order! +``` + +**Result:** "Wrong nonce" errors because transactions reach consensus nodes out of order. + +The root cause is that async calls to mirror nodes have variable latency, precheck operations complete at different speeds, and multiple relay instances can process transactions from the same sender simultaneously without any synchronization mechanism. + +To address this, the relay implements a per-sender locking mechanism that serializes transaction processing per address while allowing concurrent processing for different senders. + +--- + +### High-level behavior + +- When enabled via `ENABLE_NONCE_ORDERING`, the relay acquires a per-address lock **before any async operations or side effects**, ensuring FIFO ordering. +- Lock acquisition happens before prechecks, validation, and transaction pool updates to prevent race conditions. +- Locks are automatically released immediately after consensus submission (whether successful or failure), with a maximum hold time (default: 30 seconds) to prevent deadlocks. +- If lock acquisition fails (e.g., Redis connectivity issues), the relay fails open and processes the transaction without locking to maintain availability. +- Different senders can process transactions concurrently without blocking each other, as locks are isolated per address. + +Limitations (by design): + +- This is not an Ethereum-style mempool. Transactions are processed in arrival order, not buffered for later reordering. +- Hedera consensus nodes reject transactions with nonce gaps; users must resubmit later transactions after gaps are filled. + +--- + +### Configuration + +- `ENABLE_NONCE_ORDERING` (boolean; default: false) + - Master feature flag that enables the nonce ordering mechanism. + - When disabled, transactions are processed without any locking, maintaining current behavior. + - When enabled, transactions acquire locks before any async operations or side effects. + +- `REDIS_ENABLED` (boolean) and `REDIS_URL` (string) + - If enabled and a valid URL is provided, the relay will use Redis for distributed locking across multiple relay instances. + - If disabled or unavailable, an in-memory local locking strategy is used (single process only). + +- `LOCK_MAX_HOLD_MS` (number; default: 30000) + - Maximum time (in milliseconds) a lock can be held before automatic force release. + - Prevents deadlocks when transaction processing hangs or crashes. + +- `LOCK_QUEUE_POLL_INTERVAL_MS` (number; default: 50) + - Polling interval (in milliseconds) for Redis queue checks when waiting for lock acquisition. + - Only applicable to Redis locking strategy. + +- `LOCAL_LOCK_MAX_ENTRIES` (number; default: 1000) + - Maximum number of addresses to track in the local lock cache. + - Uses LRU eviction when limit is reached. + - Only applicable to local locking strategy. + +Strategy selection: + +- If Redis is enabled and reachable, the relay uses the distributed Redis locking strategy. +- Otherwise, it falls back to the local in-memory strategy automatically. + +--- + +### Locking strategies + +The lock service uses a strategy pattern to support both local and distributed locking. + +#### Local in-memory strategy + +- Uses the `async-mutex` library wrapped with session key tracking and automatic expiration. +- Stores lock state in an LRU cache with configurable maximum entries. +- Guarantees FIFO ordering within a single process. +- Locks are lost on process restart; state is not shared across relay instances. + +Key properties: + +- ✅ FIFO ordering guaranteed by `async-mutex` +- ✅ Per-address isolation +- ✅ Automatic cleanup via LRU cache +- ✅ Never fails (always returns a session key) +- ❌ Single process only (no distributed locking) + +#### Redis distributed strategy + +- Uses Redis `SET NX` (set if not exists) with TTL for lock ownership. +- Uses Redis `LIST` for FIFO queue of waiters. +- Polling-based acquisition (checks queue position every 50ms by default). +- Automatic TTL-based expiration handles process crashes gracefully. + +Key properties: + +- ✅ Works across multiple relay instances +- ✅ FIFO ordering via Redis queue +- ✅ Automatic cleanup via TTL on process crashes +- ✅ Fail-open behavior on errors (returns null, transaction proceeds without lock) +- ⚠️ Requires Redis availability + +Storage schema: + +``` +lock:{address} → Current lock holder's session key (SET with TTL) +lock:queue:{address} → FIFO queue of waiters (LIST) +``` + +--- + +### Lock lifecycle + +1. **Lock acquisition request** + - Transaction arrives for processing. + - Generate a unique session key (UUID) to identify this lock holder. + +2. **Wait for lock** + - Join the FIFO queue for this sender address. + - Wait until first in queue (no timeout on waiting). + - Acquire lock once available. + +3. **Lock held** + - Set ownership metadata (session key, acquisition time). + - Start automatic force-release timer (default: 30 seconds). + - Process transaction while holding the lock (validate, update transaction pool, submit to consensus). + +4. **Lock release** + - On successful submission or error, release lock. + - Verify session key matches current holder (prevents hijacking). + - Clear timer and wake next waiter in queue. + +5. **Automatic force release** + - If lock is held longer than `LOCK_MAX_HOLD_MS`, automatically release it. + - Ensures queue progresses even if transaction processing hangs or crashes. + +--- + +### Request flows + +#### eth_sendRawTransaction + +1. **Lock acquisition (before any async operations)** + - If `ENABLE_NONCE_ORDERING` is enabled, acquire lock for sender address. + - Normalize sender address (lowercase). + - If acquisition fails (Redis error), returns null but proceeds without lock (fail-open). + - Lock is acquired BEFORE any validation, side effects, or async operations to prevent race conditions. + +2. **Prechecks** (protected by lock) + - Validate transaction size, type, gas, and signature. + - Verify account exists and nonce is valid via Mirror Node. + - Add transaction to pending pool (if `ENABLE_TX_POOL` is enabled). + +3. **Transaction processing** (protected by lock) + - Submit transaction to consensus node. + - Lock is released immediately after submission completes. + +4. **Post-submission** (lock already released) + - Remove transaction from pending pool (if `ENABLE_TX_POOL` is enabled). + - Poll Mirror Node for confirmation and retrieve transaction hash (depending on `USE_ASYNC_TX_PROCESSING`). + +5. **Error handling** + - If an error occurs during prechecks or validation, release lock before throwing error. + - Lock is always released via try-catch-finally pattern to ensure cleanup. + +These rules ensure transactions from the same sender are processed in order while maintaining high availability through fail-open behavior. + +--- + +### Fail-open behavior + +When the Redis locking strategy encounters an error (e.g., network failure, connection timeout), it **fails open**: + +- `acquireLock()` returns no session key instead of a session key. +- The transaction proceeds without locking. +- An error is logged for monitoring and debugging. + +**Rationale:** + +- Availability is prioritized over strict ordering in degraded states. +- Temporary nonce ordering issues are preferable to blocking all transactions. +- Users can still submit transactions even if Redis is down. + +The local in-memory strategy never fails open because it has no external dependencies. + +--- + +### Session keys and ownership verification + +Each lock acquisition generates a unique session key (UUID) that: + +- Proves ownership when releasing the lock. +- Prevents double-release bugs. +- Prevents lock hijacking by other sessions. + +Only the session key holder can release a lock. Invalid release attempts are silently ignored. + +Example: + +```typescript +const sessionKey = await lockService.acquireLock(address); // "a1b2c3d4-5678-..." +// ... process transaction ... +await lockService.releaseLock(address, sessionKey); // Only succeeds if sessionKey matches +``` + +--- + +### Timeout strategy + +| Timeout Type | Duration | Purpose | Behavior | +| ----------------- | ------------------ | ------------------------------------------------ | --------------------------- | +| **Waiting Time** | None | Allow queue buildup without failing transactions | Waits indefinitely in queue | +| **Max Lock Time** | 30s (configurable) | Prevent deadlocks from hung transactions | Force release after 30s | + +**Design decision:** No timeout on waiting in queue because the max lock time provides sufficient protection. If the current holder hangs, force release kicks in after 30 seconds and the queue progresses. + +--- + +### Compatibility with async transaction processing + +The lock service is fully compatible with `USE_ASYNC_TX_PROCESSING`: + +- Lock is acquired before any prechecks or validation (synchronously in the main request path). +- When async mode is enabled, the transaction hash is returned immediately after prechecks pass. +- The lock persists across the async boundary during background processing. +- The lock is released after consensus submission completes in the background. +- Session key is passed to the async processor to ensure correct ownership. +- If an error occurs during prechecks (before async processing starts), the lock is released immediately. + +--- + +### Monitoring and observability + +The lock service logs the following events at appropriate levels: + +- **Debug:** Lock acquisition/release with hold times and queue lengths +- **Trace:** Detailed lock lifecycle events (queue join, polling, acquisition) +- **Error:** Lock acquisition failures with fail-open behavior + +Key metrics to monitor: + +- Lock hold times (should be well under 30 seconds) +- Queue lengths (high values indicate congestion) +- Failed lock acquisitions (indicates Redis issues) +- Force releases (indicates hung transactions or timeouts) + +--- + +### FAQ + +#### Does this guarantee out-of-order nonce execution without resubmission? + +No. Hedera consensus nodes do not maintain an execution buffer by nonce. This feature ensures transactions are submitted in order, but if a nonce gap exists when a transaction reaches the consensus node, it will be rejected and must be resubmitted. + +#### Can transactions from different senders process in parallel? + +Yes! Locks are per-sender address. Different senders have independent locks and process concurrently without blocking each other. + +#### What happens if a transaction crashes while holding the lock? + +The automatic force-release timer (default: 30 seconds) will release the lock. The next waiter in queue will be awakened and can proceed. + +#### What happens if Redis goes down? + +The Redis locking strategy fails open: transactions proceed without locking. Once Redis is restored, the relay automatically resumes using distributed locks. No manual intervention is required. + +#### Why no timeout on waiting in queue? + +The max lock time (30 seconds) provides sufficient protection. If the current holder hangs, they'll be force-released after 30 seconds and the queue progresses. Adding a wait timeout would cause later transactions to fail unnecessarily. + +#### If 100 transactions are waiting in queue and the first one hangs, won't they all timeout? + +No. Each transaction gets its own fresh 30-second window **after acquiring the lock**. The timer starts only when you hold the lock, not when you join the queue: + +``` +t=0s: Tx1 acquires lock → 30s timer starts for Tx1 +t=1s: Tx2-100 join queue → NO timers yet, just waiting +t=30s: Tx1's timer expires → Force released +t=30s: Tx2 acquires lock → NEW 30s timer starts for Tx2 +t=35s: Tx2 completes and releases +t=35s: Tx3 acquires lock → NEW 30s timer starts for Tx3 +``` + +Each transaction in the queue gets a full 30 seconds to process once they acquire the lock. + +#### Does this work with the transaction pool feature (`ENABLE_TX_POOL`)? + +Yes! The lock service and transaction pool work together: + +1. Lock is acquired for the sender address (before any operations) +2. Transaction prechecks are performed (protected by lock) +3. Transaction is added to the pending pool (protected by lock) +4. Transaction is submitted to consensus node (protected by lock) +5. Lock is released immediately after submission +6. Transaction is removed from pending pool after consensus (no longer needs lock) + +Both features are independent and can be enabled/disabled separately. + +#### How do I enable this feature? + +Set the environment variable `ENABLE_NONCE_ORDERING=true`. The feature is disabled by default to allow for gradual rollout and testing. + +#### What if I don't use Redis? Do I still get ordering guarantees? + +Yes, but only within a single relay instance. The local in-memory strategy ensures FIFO ordering for transactions processed by the same relay process. If you run multiple relay instances without Redis, each instance has its own locks and cannot coordinate with others. diff --git a/package-lock.json b/package-lock.json index a332ee51ff..73b34ae831 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,7 +78,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -133,7 +132,6 @@ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -174,7 +172,6 @@ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0", @@ -191,7 +188,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/compat-data": "^7.26.8", "@babel/helper-validator-option": "^7.25.9", @@ -208,7 +204,6 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "license": "ISC", - "peer": true, "dependencies": { "yallist": "^3.0.2" } @@ -217,15 +212,13 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/@babel/helper-module-imports": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" @@ -239,7 +232,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", @@ -257,7 +249,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -267,7 +258,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -286,7 +276,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -296,7 +285,6 @@ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/template": "^7.27.0", "@babel/types": "^7.27.0" @@ -310,7 +298,6 @@ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.27.0" }, @@ -326,7 +313,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -339,7 +325,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -352,7 +337,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -365,7 +349,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -381,7 +364,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.9" }, @@ -397,7 +379,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -410,7 +391,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -423,7 +403,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -436,7 +415,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -449,7 +427,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -462,7 +439,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -475,7 +451,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -488,7 +463,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -501,7 +475,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -517,7 +490,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -533,7 +505,6 @@ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", "license": "MIT", - "peer": true, "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -546,7 +517,6 @@ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.27.0", @@ -561,7 +531,6 @@ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", @@ -581,7 +550,6 @@ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", @@ -600,7 +568,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -610,7 +577,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -620,7 +586,6 @@ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" @@ -2447,7 +2412,6 @@ "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -2456,7 +2420,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "peer": true, "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -2472,7 +2435,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -2481,7 +2443,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -2494,7 +2455,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -2507,7 +2467,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -2519,7 +2478,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -2534,7 +2492,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -2546,7 +2503,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "peer": true, "engines": { "node": ">=8" } @@ -2564,7 +2520,6 @@ "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3" }, @@ -2585,7 +2540,6 @@ "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "license": "MIT", - "peer": true, "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -2601,7 +2555,6 @@ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -2619,7 +2572,6 @@ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@sinonjs/commons": "^3.0.0" } @@ -2637,7 +2589,6 @@ "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "license": "MIT", - "peer": true, "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -2650,7 +2601,6 @@ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -2677,7 +2627,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2693,7 +2642,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2710,7 +2658,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2722,15 +2669,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@jest/transform/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -2740,7 +2685,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -2753,7 +2697,6 @@ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "license": "ISC", - "peer": true, "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -2767,7 +2710,6 @@ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -2785,7 +2727,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2801,7 +2742,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2818,7 +2758,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2830,15 +2769,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@jest/types/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -2848,7 +2785,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -2861,7 +2797,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -2884,7 +2819,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "license": "MIT", - "peer": true, "engines": { "node": ">=6.0.0" } @@ -2894,7 +2828,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -4292,6 +4225,7 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", + "peer": true, "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", @@ -4563,7 +4497,6 @@ "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.1.tgz", "integrity": "sha512-q5BwZtL0YbaJRgofl8qrD9BNdGJkecTJNYG8VFOVQYXPTBa3ZSooip1aj0wrjoa0HloKx/Hmx5UMvuhfEsjn8A==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -4573,7 +4506,6 @@ "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.79.1.tgz", "integrity": "sha512-cTVXfCICkmUU6UvUpnLP4BE82O14JRuVz42cg/A19oasTaZmzHl0+uIDzt2cZEbt/N2sJ/EZnZL61qqpwbNXWQ==", "license": "MIT", - "peer": true, "dependencies": { "glob": "^7.1.1", "hermes-parser": "0.25.1", @@ -4593,7 +4525,6 @@ "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.79.1.tgz", "integrity": "sha512-hqCMQrMRi19G7yxEsYwV9A0MHB6Hri7B5dytRD7kU5vtz0Lzg1fZYYvmS0x9OdWJWPntmHA8xiijwM+4cT8cpQ==", "license": "MIT", - "peer": true, "dependencies": { "@react-native/dev-middleware": "0.79.1", "chalk": "^4.0.0", @@ -4621,7 +4552,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -4637,7 +4567,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -4654,7 +4583,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -4666,15 +4594,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@react-native/community-cli-plugin/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -4684,7 +4610,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -4693,15 +4618,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@react-native/community-cli-plugin/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -4714,7 +4637,6 @@ "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.79.1.tgz", "integrity": "sha512-IgbQM/djzBhkkjzIT/b36zwkc4UMxZLTKgRVJrSEjuwtOPmgfh/1F5m3OUitbMd4/e06VgN0vPLyBzToj1kiwA==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=18" } @@ -4724,7 +4646,6 @@ "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.79.1.tgz", "integrity": "sha512-xegUHwi6h8wOLIl/9ImZoIVVwzecE+ENGTELIrD2PsseBbtdRMKzZ8A1LTBjPPt3IjHPH6103JcSPwgepP6zFA==", "license": "MIT", - "peer": true, "dependencies": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.79.1", @@ -4747,7 +4668,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -4756,15 +4676,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@react-native/dev-middleware/node_modules/open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", - "peer": true, "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -4781,7 +4699,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", "license": "MIT", - "peer": true, "dependencies": { "async-limiter": "~1.0.0" } @@ -4791,7 +4708,6 @@ "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.79.1.tgz", "integrity": "sha512-vfoNcOBig/+R7g3eqHkBSbSVkk0NMPzyXE5QY0V+/0flRa3kDZUHP2fr8ygoY/4rxbi05wPME2/dTEuoYcpnjg==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -4801,7 +4717,6 @@ "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.79.1.tgz", "integrity": "sha512-P8j11kdD+ehL5jqHSCM1BOl4SnJ+3rvGPpsagAqyngU6WSausISO7YFufltrWA7kdpHdnAL2HfJJ62szTRGShw==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -4810,15 +4725,13 @@ "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.79.1.tgz", "integrity": "sha512-Fj12xKyihZhrFH45ruqECd2JVx9lyYe+dyxO7MYgkqY6UENsSS3JKcfzjSNBZLW7NXts6JkbaqLQPwaHmPF7QA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@react-native/virtualized-lists": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.79.1.tgz", "integrity": "sha512-v1KeqJeVJXjc2mewjKQYSay7D7+VSacxryejuuVXlPE9E9wVbzMPCfPjbIS8C9nMC7a4rsRFilX7RVKYkeZaGg==", "license": "MIT", - "peer": true, "dependencies": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" @@ -4852,6 +4765,7 @@ "version": "5.8.0", "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.8.0.tgz", "integrity": "sha512-ywZjKGoSSAECGYOd9bJpws6d4867SN686obUWT/sRmo1c/Q8V+jWyInvlqwKa0BOvTHHwYeB2WFUEvd6PADeOQ==", + "peer": true, "dependencies": { "cluster-key-slot": "1.1.2" }, @@ -5029,8 +4943,7 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@sinonjs/commons": { "version": "3.0.1", @@ -5164,7 +5077,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -5178,7 +5090,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.0.0" } @@ -5188,7 +5099,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "license": "MIT", - "peer": true, "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -5199,7 +5109,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.20.7" } @@ -5324,7 +5233,6 @@ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*" } @@ -5352,7 +5260,6 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "license": "MIT", - "peer": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -5362,7 +5269,6 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "license": "MIT", - "peer": true, "dependencies": { "@types/istanbul-lib-report": "*" } @@ -5446,6 +5352,7 @@ "version": "24.9.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", + "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -5526,8 +5433,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/uuid": { "version": "10.0.0", @@ -5541,7 +5447,6 @@ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "license": "MIT", - "peer": true, "dependencies": { "@types/yargs-parser": "*" } @@ -5550,8 +5455,7 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/@types/yauzl": { "version": "2.10.3", @@ -5610,6 +5514,7 @@ "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -5896,7 +5801,6 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "license": "MIT", - "peer": true, "dependencies": { "event-target-shim": "^5.0.0" }, @@ -5922,6 +5826,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -6041,8 +5946,7 @@ "version": "1.4.10", "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ansi-colors": { "version": "4.1.3", @@ -6075,7 +5979,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "peer": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -6156,8 +6059,7 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/asn1": { "version": "0.2.6", @@ -6188,7 +6090,6 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "*" } @@ -6202,8 +6103,16 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, + "node_modules/async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", "license": "MIT", - "peer": true + "dependencies": { + "tslib": "^2.4.0" + } }, "node_modules/asynckit": { "version": "0.4.0", @@ -6222,6 +6131,7 @@ "version": "1.12.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "peer": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -6246,7 +6156,6 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "license": "MIT", - "peer": true, "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -6268,7 +6177,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -6284,7 +6192,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -6301,7 +6208,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -6313,15 +6219,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/babel-jest/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -6331,7 +6235,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -6344,7 +6247,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -6361,7 +6263,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -6378,7 +6279,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "license": "MIT", - "peer": true, "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -6394,7 +6294,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz", "integrity": "sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==", "license": "MIT", - "peer": true, "dependencies": { "hermes-parser": "0.25.1" } @@ -6404,7 +6303,6 @@ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -6431,7 +6329,6 @@ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "license": "MIT", - "peer": true, "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -6675,7 +6572,6 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "node-int64": "^0.4.0" } @@ -7039,7 +6935,6 @@ "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", "license": "MIT", - "peer": true, "dependencies": { "callsites": "^2.0.0" }, @@ -7052,7 +6947,6 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -7062,7 +6956,6 @@ "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", "license": "MIT", - "peer": true, "dependencies": { "caller-callsite": "^2.0.0" }, @@ -7120,8 +7013,7 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "CC-BY-4.0", - "peer": true + "license": "CC-BY-4.0" }, "node_modules/chai": { "version": "4.5.0", @@ -7174,7 +7066,6 @@ "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "get-func-name": "^2.0.2" }, @@ -7188,7 +7079,6 @@ "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -7258,7 +7148,6 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -7277,7 +7166,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -7290,7 +7178,6 @@ "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -7305,7 +7192,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -7318,7 +7204,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "license": "MIT", - "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -7655,7 +7540,6 @@ "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "license": "MIT", - "peer": true, "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -7671,7 +7555,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -7680,8 +7563,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/console-control-strings": { "version": "1.1.0", @@ -8022,7 +7904,6 @@ "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "type-detect": "^4.0.0" }, @@ -8291,8 +8172,7 @@ "version": "1.5.145", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.145.tgz", "integrity": "sha512-pZ5EcTWRq/055MvSBgoFEyKf2i4apwfoqJbK/ak2jnFq8oHjZ+vzc3AhRcz37Xn+ZJfL58R666FLJx0YOK9yTw==", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/elliptic": { "version": "6.6.1", @@ -8430,7 +8310,6 @@ "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", "license": "MIT", - "peer": true, "dependencies": { "stackframe": "^1.3.4" } @@ -8507,6 +8386,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.34.0.tgz", "integrity": "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==", "dev": true, + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -8920,7 +8800,6 @@ "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -9005,7 +8884,6 @@ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -9167,7 +9045,6 @@ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "license": "Apache-2.0", - "peer": true, "dependencies": { "bser": "2.1.1" } @@ -9257,7 +9134,6 @@ "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "license": "MIT", - "peer": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -9276,7 +9152,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -9285,15 +9160,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/finalhandler/node_modules/on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "license": "MIT", - "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -9384,8 +9257,7 @@ "version": "0.0.6", "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -9538,6 +9410,20 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -9551,7 +9437,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true, "engines": { "node": ">=6.9.0" } @@ -9582,7 +9467,6 @@ "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "*" } @@ -9615,7 +9499,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -10055,15 +9938,13 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "license": "MIT", - "peer": true, "dependencies": { "hermes-estree": "0.25.1" } @@ -10259,7 +10140,6 @@ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", "license": "MIT", - "peer": true, "dependencies": { "queue": "6.0.2" }, @@ -10403,7 +10283,6 @@ "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.0.0" } @@ -10471,7 +10350,6 @@ "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -10903,7 +10781,6 @@ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "license": "MIT", - "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -10921,7 +10798,6 @@ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "license": "MIT", - "peer": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -10931,7 +10807,6 @@ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -10957,7 +10832,6 @@ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -10978,7 +10852,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -10994,7 +10867,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11011,7 +10883,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11023,15 +10894,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-message-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -11041,7 +10910,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -11054,7 +10922,6 @@ "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -11069,7 +10936,6 @@ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "license": "MIT", - "peer": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -11079,7 +10945,6 @@ "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -11097,7 +10962,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -11113,7 +10977,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11130,7 +10993,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11142,15 +11004,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -11160,7 +11020,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -11173,7 +11032,6 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -11191,7 +11049,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -11207,7 +11064,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -11220,7 +11076,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11237,7 +11092,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11249,15 +11103,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jest-validate/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -11267,7 +11119,6 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -11277,7 +11128,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -11290,7 +11140,6 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "license": "MIT", - "peer": true, "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -11306,7 +11155,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -11316,7 +11164,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -11365,15 +11212,13 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "license": "MIT", - "peer": true, "bin": { "jsesc": "bin/jsesc" }, @@ -12217,7 +12062,6 @@ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", "license": "Apache-2.0", - "peer": true, "dependencies": { "debug": "^2.6.9", "marky": "^1.2.2" @@ -12228,7 +12072,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -12237,8 +12080,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lilconfig": { "version": "3.1.3", @@ -12472,8 +12314,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", @@ -12766,7 +12607,6 @@ "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", - "peer": true, "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -12780,7 +12620,6 @@ "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "get-func-name": "^2.0.1" } @@ -12954,7 +12793,6 @@ "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "license": "BSD-3-Clause", - "peer": true, "dependencies": { "tmpl": "1.0.5" } @@ -12974,8 +12812,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/math-intrinsics": { "version": "1.1.0", @@ -13016,8 +12853,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/meow": { "version": "8.1.2", @@ -13191,7 +13027,6 @@ "resolved": "https://registry.npmjs.org/metro/-/metro-0.82.2.tgz", "integrity": "sha512-hOBd4O4Cn/tLf3jz7IjSgD/A66MqMzgZuyF1I/pmNwYcY3q3j2vbh7Fa09KIbvUq5Yz7BewU356XboaEtEXPgA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", @@ -13246,7 +13081,6 @@ "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.82.2.tgz", "integrity": "sha512-c2gesA7/B4dovPmmYC2HziNXb4XFG3YkQ9FjEzwRnR6KH2hT7nJn6mkcri1h85r3sMttpnmoBuZ8WDz980Zhlw==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", @@ -13261,15 +13095,13 @@ "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.28.1.tgz", "integrity": "sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/metro-babel-transformer/node_modules/hermes-parser": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.28.1.tgz", "integrity": "sha512-nf8o+hE8g7UJWParnccljHumE9Vlq8F7MqIdeahl+4x0tvCUJYRrT0L7h0MMg/X9YJmkNwsfbaNNrzPtFXOscg==", "license": "MIT", - "peer": true, "dependencies": { "hermes-estree": "0.28.1" } @@ -13279,7 +13111,6 @@ "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.82.2.tgz", "integrity": "sha512-MxY4xvPKuE68NYpKJjH8YvVVugDL2QcuTracHsV5/30ZIaRr0v1QuAX5vt45OCQDQQWeh1rDv3E4JB6AbIvnZQ==", "license": "MIT", - "peer": true, "dependencies": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", @@ -13295,7 +13126,6 @@ "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.82.2.tgz", "integrity": "sha512-lfjC9zzSri+rS7lkoCh04LniFga8JQVUqSuscD9KraIm9zRzwIwvaMx8V6Oogiezs+FAJUOSnVNhHcHc9l8H2Q==", "license": "MIT", - "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6" }, @@ -13308,7 +13138,6 @@ "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.82.2.tgz", "integrity": "sha512-0dG3qCFLoE3ddNexAxSLJ7FbGjEbwUjDNOgYeCLoPSkKB01k5itvvr2HFfl2HisOCfLcpjpVzF5NtB/O71lxfA==", "license": "MIT", - "peer": true, "dependencies": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", @@ -13328,7 +13157,6 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "license": "MIT", - "peer": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -13338,7 +13166,6 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", "license": "MIT", - "peer": true, "dependencies": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", @@ -13354,7 +13181,6 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", "license": "MIT", - "peer": true, "dependencies": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" @@ -13368,7 +13194,6 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "license": "MIT", - "peer": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -13382,7 +13207,6 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "license": "MIT", - "peer": true, "dependencies": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -13396,7 +13220,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -13406,7 +13229,6 @@ "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.82.2.tgz", "integrity": "sha512-d2XMkWbRh6PdPV1OZ8OyUyDWrtEbQ1m5ASpKtemLPbujfoE4RlwFZdl4ljfBNVVZ1s0z7tgsSFwKMyTeXgjtSg==", "license": "MIT", - "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", @@ -13421,7 +13243,6 @@ "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.82.2.tgz", "integrity": "sha512-pax0WA80eRH096YO0kwox+ZD5im3V0Vswr2x1YqdMcZVWlr6uwXgQdo9q+mpcvJ1k77J+hmY5HIg71bqrUptVg==", "license": "MIT", - "peer": true, "dependencies": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", @@ -13442,7 +13263,6 @@ "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.82.2.tgz", "integrity": "sha512-+nveaEdQUvsoi0OSr4Cp+btevZsg2DKsu8kUJsvyLIcRRFPUw9CwzF3V2cA5b55DY5LcIJyAcZf4D9ARKfoilQ==", "license": "MIT", - "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" @@ -13456,7 +13276,6 @@ "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.82.2.tgz", "integrity": "sha512-Who2hGzq2aCGSsBaQBU0L3SADiy/kj/gv0coujNWziRY4SKq7ECKzWqtVk1JlEF7IGXDDRDxEgFuLmPV6mZGVQ==", "license": "MIT", - "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6" }, @@ -13469,7 +13288,6 @@ "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.82.2.tgz", "integrity": "sha512-gEcb2AfDs3GRs2SFjtEmG0k61B/cZEVCbh6cSmkjJpyHr+VRjw77MnDpX9AUcJYa4bCT63E7IEySOMM0Z8p87g==", "license": "MIT", - "peer": true, "dependencies": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" @@ -13483,7 +13301,6 @@ "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.82.2.tgz", "integrity": "sha512-S26xPdz1/EeAY0HqaPXfny8CeiY0Dvl4sBLQiXGXhoES4gUDAuMhA1tioKrv5F+x68Sod8cp8Js6EGqbMXeqMA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", @@ -13505,7 +13322,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13515,7 +13331,6 @@ "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.82.2.tgz", "integrity": "sha512-iheanMnOMned6gjt6sKSfU5AoNyV6pJyQAWydwuHcjhGpa/kiAM0kKmw23qHejELK89Yw8HDZ3Fd/5l1jxpFVA==", "license": "MIT", - "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", @@ -13536,7 +13351,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13546,7 +13360,6 @@ "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.82.2.tgz", "integrity": "sha512-kEveuEVxghTEXkDiyY0MT5QRqei092KJG46nduo0VghFgI6QFodbAjFit1ULyWsn2VOTGSUDJ3VgHBMy7MaccA==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", @@ -13564,7 +13377,6 @@ "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.82.2.tgz", "integrity": "sha512-MJQNz6cGjqewCRqFmPrsHu6Oe93v2B6zgHkrNxQ6XdPMJz5VHD33m8q+8UsNJOH8wUMoRu5JmYtuUTIVIFxh2A==", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", @@ -13589,7 +13401,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -13605,7 +13416,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -13621,15 +13431,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/metro/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -13641,15 +13449,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/metro/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -13658,15 +13464,13 @@ "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.28.1.tgz", "integrity": "sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/metro/node_modules/hermes-parser": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.28.1.tgz", "integrity": "sha512-nf8o+hE8g7UJWParnccljHumE9Vlq8F7MqIdeahl+4x0tvCUJYRrT0L7h0MMg/X9YJmkNwsfbaNNrzPtFXOscg==", "license": "MIT", - "peer": true, "dependencies": { "hermes-estree": "0.28.1" } @@ -13676,7 +13480,6 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "license": "BSD-3-Clause", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -13686,7 +13489,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -13699,7 +13501,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8.3.0" }, @@ -13733,7 +13534,6 @@ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "license": "MIT", - "peer": true, "bin": { "mime": "cli.js" }, @@ -13994,6 +13794,7 @@ "integrity": "sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "browser-stdout": "^1.3.1", "chokidar": "^4.0.1", @@ -14426,8 +14227,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/node-machine-id": { "version": "1.1.12", @@ -14438,8 +14238,7 @@ "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/nopt": { "version": "8.1.0", @@ -14495,7 +14294,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -14646,14 +14444,14 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/nx": { "version": "21.6.6", "resolved": "https://registry.npmjs.org/nx/-/nx-21.6.6.tgz", "integrity": "sha512-KybewPwpU+8Vdqd6xwSh5sWlsXTGs9a2L7np+rsTTBQvNshNHl1R1nRExRB1L50od0wnnBm/5A2BB0jvO10IWw==", "hasInstallScript": true, + "peer": true, "dependencies": { "@napi-rs/wasm-runtime": "0.2.4", "@yarnpkg/lockfile": "^1.1.0", @@ -14822,7 +14620,6 @@ "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.82.2.tgz", "integrity": "sha512-sfUaYpjkAdHgu8cXLAyWXO98jW1EUOStTDNslfC9eb3tBLExe67PRqh09J0xdD6AlFKHFGTvXPbuHGvlrZNJNA==", "license": "MIT", - "peer": true, "dependencies": { "flow-enums-runtime": "^0.0.6" }, @@ -15610,7 +15407,6 @@ "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": "*" } @@ -15773,7 +15569,6 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 6" } @@ -15894,7 +15689,6 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "license": "MIT", - "peer": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -15909,7 +15703,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -15971,7 +15764,6 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", "license": "MIT", - "peer": true, "dependencies": { "asap": "~2.0.6" } @@ -16103,7 +15895,6 @@ "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", "license": "MIT", - "peer": true, "dependencies": { "inherits": "~2.0.3" } @@ -16155,7 +15946,6 @@ "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -16215,7 +16005,6 @@ "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.1.tgz", "integrity": "sha512-TFo1MEnkqE6hzAbaztnyR5uLTMoz6wnEWwWBsCUzNt+sVXJycuRJdDqvL078M4/h65BI/YO5XWTaxZDWVsW0fw==", "license": "MIT", - "peer": true, "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" @@ -16226,7 +16015,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8.3.0" }, @@ -16326,7 +16114,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -16342,7 +16129,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -16359,7 +16145,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -16371,15 +16156,13 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-native/node_modules/commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -16389,7 +16172,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -16398,15 +16180,13 @@ "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/react-native/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -16419,7 +16199,6 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", "license": "MIT", - "peer": true, "dependencies": { "async-limiter": "~1.0.0" } @@ -16429,7 +16208,6 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -16821,8 +16599,7 @@ "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/replace": { "version": "1.2.2", @@ -17184,8 +16961,7 @@ "version": "0.25.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/secure-json-parse": { "version": "2.7.0", @@ -17222,7 +16998,6 @@ "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "license": "MIT", - "peer": true, "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -17247,7 +17022,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -17256,15 +17030,13 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/send/node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "license": "MIT", - "peer": true, "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -17281,7 +17053,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -17291,7 +17062,6 @@ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -17311,7 +17081,6 @@ "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "license": "MIT", - "peer": true, "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -17327,7 +17096,6 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -17367,7 +17135,6 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4" }, @@ -17564,7 +17331,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "peer": true, "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -17677,7 +17443,6 @@ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "license": "MIT", - "peer": true, "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -17690,7 +17455,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -17699,15 +17463,13 @@ "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/stacktrace-parser": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", "license": "MIT", - "peer": true, "dependencies": { "type-fest": "^0.7.1" }, @@ -17720,7 +17482,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=8" } @@ -17986,7 +17747,6 @@ "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -18004,14 +17764,12 @@ "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "peer": true, "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -18041,8 +17799,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/through": { "version": "2.3.8", @@ -18120,6 +17877,7 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "peer": true, "engines": { "node": ">=12" }, @@ -18142,8 +17900,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "license": "BSD-3-Clause", - "peer": true + "license": "BSD-3-Clause" }, "node_modules/to-regex-range": { "version": "5.0.1", @@ -18271,6 +18028,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -18482,6 +18240,7 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -18580,7 +18339,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -18629,7 +18387,6 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4.0" } @@ -18698,8 +18455,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/walk-up-path": { "version": "4.0.0", @@ -18714,7 +18470,6 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "makeerror": "1.0.12" } @@ -19193,6 +18948,7 @@ "dependencies": { "@hashgraph/json-rpc-config-service": "file:../config-service", "@hashgraph/sdk": "^2.63.0", + "async-mutex": "^0.5.0", "axios": "^1.4.0", "axios-retry": "^4.5.0", "better-lookup": "^1.3.0", @@ -20161,7 +19917,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "peer": true, "requires": { "@jridgewell/gen-mapping": "^0.3.0", "@jridgewell/trace-mapping": "^0.3.9" @@ -20201,8 +19956,7 @@ "@babel/compat-data": { "version": "7.26.8", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "peer": true + "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==" }, "@babel/core": { "version": "7.26.10", @@ -20231,7 +19985,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", - "peer": true, "requires": { "@babel/parser": "^7.27.0", "@babel/types": "^7.27.0", @@ -20244,7 +19997,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", - "peer": true, "requires": { "@babel/compat-data": "^7.26.8", "@babel/helper-validator-option": "^7.25.9", @@ -20257,7 +20009,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "peer": true, "requires": { "yallist": "^3.0.2" } @@ -20265,8 +20016,7 @@ "yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "peer": true + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" } } }, @@ -20274,7 +20024,6 @@ "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "peer": true, "requires": { "@babel/traverse": "^7.25.9", "@babel/types": "^7.25.9" @@ -20284,7 +20033,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "peer": true, "requires": { "@babel/helper-module-imports": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9", @@ -20294,14 +20042,12 @@ "@babel/helper-plugin-utils": { "version": "7.26.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", - "peer": true + "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==" }, "@babel/helper-string-parser": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "peer": true + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==" }, "@babel/helper-validator-identifier": { "version": "7.25.9", @@ -20311,14 +20057,12 @@ "@babel/helper-validator-option": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "peer": true + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==" }, "@babel/helpers": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", - "peer": true, "requires": { "@babel/template": "^7.27.0", "@babel/types": "^7.27.0" @@ -20328,7 +20072,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "peer": true, "requires": { "@babel/types": "^7.27.0" } @@ -20337,7 +20080,6 @@ "version": "7.8.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -20346,7 +20088,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -20355,7 +20096,6 @@ "version": "7.12.13", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.12.13" } @@ -20364,7 +20104,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } @@ -20373,7 +20112,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.26.0.tgz", "integrity": "sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.25.9" } @@ -20382,7 +20120,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -20391,7 +20128,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -20400,7 +20136,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -20409,7 +20144,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -20418,7 +20152,6 @@ "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" } @@ -20427,7 +20160,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -20436,7 +20168,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -20445,7 +20176,6 @@ "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.8.0" } @@ -20454,7 +20184,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } @@ -20463,7 +20192,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } @@ -20472,7 +20200,6 @@ "version": "7.26.7", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.7.tgz", "integrity": "sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==", - "peer": true, "requires": { "regenerator-runtime": "^0.14.0" } @@ -20481,7 +20208,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", - "peer": true, "requires": { "@babel/code-frame": "^7.26.2", "@babel/parser": "^7.27.0", @@ -20492,7 +20218,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", - "peer": true, "requires": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", @@ -20506,8 +20231,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "peer": true + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" } } }, @@ -20515,7 +20239,6 @@ "version": "npm:@babel/traverse@7.27.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", - "peer": true, "requires": { "@babel/code-frame": "^7.26.2", "@babel/generator": "^7.27.0", @@ -20529,8 +20252,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "peer": true + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" } } }, @@ -20538,7 +20260,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "peer": true, "requires": { "@babel/helper-string-parser": "^7.25.9", "@babel/helper-validator-identifier": "^7.25.9" @@ -21266,6 +20987,7 @@ "@types/chai": "^5.2.3", "@types/mocha": "^10.0.10", "@types/node": "^24.9.1", + "async-mutex": "^0.5.0", "axios": "^1.4.0", "axios-retry": "^4.5.0", "better-lookup": "^1.3.0", @@ -22387,14 +22109,12 @@ "@isaacs/ttlcache": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", - "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", - "peer": true + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==" }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "peer": true, "requires": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -22407,7 +22127,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, "requires": { "sprintf-js": "~1.0.2" } @@ -22416,7 +22135,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "peer": true, "requires": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -22426,7 +22144,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "peer": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -22436,7 +22153,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "peer": true, "requires": { "p-locate": "^4.1.0" } @@ -22445,7 +22161,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "peer": true, "requires": { "p-try": "^2.0.0" } @@ -22454,7 +22169,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "peer": true, "requires": { "p-limit": "^2.2.0" } @@ -22462,8 +22176,7 @@ "resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "peer": true + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" } } }, @@ -22476,7 +22189,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", - "peer": true, "requires": { "@jest/types": "^29.6.3" } @@ -22490,7 +22202,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", - "peer": true, "requires": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -22502,7 +22213,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", - "peer": true, "requires": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -22516,7 +22226,6 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "peer": true, "requires": { "@sinonjs/commons": "^3.0.0" } @@ -22532,7 +22241,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "peer": true, "requires": { "@sinclair/typebox": "^0.27.8" } @@ -22541,7 +22249,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", - "peer": true, "requires": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -22564,7 +22271,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -22573,7 +22279,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -22583,7 +22288,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -22591,20 +22295,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -22613,7 +22314,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "peer": true, "requires": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -22625,7 +22325,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "peer": true, "requires": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -22639,7 +22338,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -22648,7 +22346,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -22658,7 +22355,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -22666,20 +22362,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -22690,7 +22383,6 @@ "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "peer": true, "requires": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -22705,14 +22397,12 @@ "@jridgewell/set-array": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "peer": true + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" }, "@jridgewell/source-map": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", - "peer": true, "requires": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25" @@ -23718,6 +23408,7 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz", "integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==", + "peer": true, "requires": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", @@ -23938,14 +23629,12 @@ "@react-native/assets-registry": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.79.1.tgz", - "integrity": "sha512-q5BwZtL0YbaJRgofl8qrD9BNdGJkecTJNYG8VFOVQYXPTBa3ZSooip1aj0wrjoa0HloKx/Hmx5UMvuhfEsjn8A==", - "peer": true + "integrity": "sha512-q5BwZtL0YbaJRgofl8qrD9BNdGJkecTJNYG8VFOVQYXPTBa3ZSooip1aj0wrjoa0HloKx/Hmx5UMvuhfEsjn8A==" }, "@react-native/codegen": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.79.1.tgz", "integrity": "sha512-cTVXfCICkmUU6UvUpnLP4BE82O14JRuVz42cg/A19oasTaZmzHl0+uIDzt2cZEbt/N2sJ/EZnZL61qqpwbNXWQ==", - "peer": true, "requires": { "glob": "^7.1.1", "hermes-parser": "0.25.1", @@ -23958,7 +23647,6 @@ "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.79.1.tgz", "integrity": "sha512-hqCMQrMRi19G7yxEsYwV9A0MHB6Hri7B5dytRD7kU5vtz0Lzg1fZYYvmS0x9OdWJWPntmHA8xiijwM+4cT8cpQ==", - "peer": true, "requires": { "@react-native/dev-middleware": "0.79.1", "chalk": "^4.0.0", @@ -23974,7 +23662,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -23983,7 +23670,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -23993,7 +23679,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -24001,14 +23686,12 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "peer": true, "requires": { "ms": "2.0.0" } @@ -24016,20 +23699,17 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -24039,14 +23719,12 @@ "@react-native/debugger-frontend": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.79.1.tgz", - "integrity": "sha512-IgbQM/djzBhkkjzIT/b36zwkc4UMxZLTKgRVJrSEjuwtOPmgfh/1F5m3OUitbMd4/e06VgN0vPLyBzToj1kiwA==", - "peer": true + "integrity": "sha512-IgbQM/djzBhkkjzIT/b36zwkc4UMxZLTKgRVJrSEjuwtOPmgfh/1F5m3OUitbMd4/e06VgN0vPLyBzToj1kiwA==" }, "@react-native/dev-middleware": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.79.1.tgz", "integrity": "sha512-xegUHwi6h8wOLIl/9ImZoIVVwzecE+ENGTELIrD2PsseBbtdRMKzZ8A1LTBjPPt3IjHPH6103JcSPwgepP6zFA==", - "peer": true, "requires": { "@isaacs/ttlcache": "^1.4.1", "@react-native/debugger-frontend": "0.79.1", @@ -24065,7 +23743,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "peer": true, "requires": { "ms": "2.0.0" } @@ -24073,14 +23750,12 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "peer": true, "requires": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -24090,7 +23765,6 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", - "peer": true, "requires": { "async-limiter": "~1.0.0" } @@ -24100,26 +23774,22 @@ "@react-native/gradle-plugin": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.79.1.tgz", - "integrity": "sha512-vfoNcOBig/+R7g3eqHkBSbSVkk0NMPzyXE5QY0V+/0flRa3kDZUHP2fr8ygoY/4rxbi05wPME2/dTEuoYcpnjg==", - "peer": true + "integrity": "sha512-vfoNcOBig/+R7g3eqHkBSbSVkk0NMPzyXE5QY0V+/0flRa3kDZUHP2fr8ygoY/4rxbi05wPME2/dTEuoYcpnjg==" }, "@react-native/js-polyfills": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.79.1.tgz", - "integrity": "sha512-P8j11kdD+ehL5jqHSCM1BOl4SnJ+3rvGPpsagAqyngU6WSausISO7YFufltrWA7kdpHdnAL2HfJJ62szTRGShw==", - "peer": true + "integrity": "sha512-P8j11kdD+ehL5jqHSCM1BOl4SnJ+3rvGPpsagAqyngU6WSausISO7YFufltrWA7kdpHdnAL2HfJJ62szTRGShw==" }, "@react-native/normalize-colors": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.79.1.tgz", - "integrity": "sha512-Fj12xKyihZhrFH45ruqECd2JVx9lyYe+dyxO7MYgkqY6UENsSS3JKcfzjSNBZLW7NXts6JkbaqLQPwaHmPF7QA==", - "peer": true + "integrity": "sha512-Fj12xKyihZhrFH45ruqECd2JVx9lyYe+dyxO7MYgkqY6UENsSS3JKcfzjSNBZLW7NXts6JkbaqLQPwaHmPF7QA==" }, "@react-native/virtualized-lists": { "version": "0.79.1", "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.79.1.tgz", "integrity": "sha512-v1KeqJeVJXjc2mewjKQYSay7D7+VSacxryejuuVXlPE9E9wVbzMPCfPjbIS8C9nMC7a4rsRFilX7RVKYkeZaGg==", - "peer": true, "requires": { "invariant": "^2.2.4", "nullthrows": "^1.1.1" @@ -24135,6 +23805,7 @@ "version": "5.8.0", "resolved": "https://registry.npmjs.org/@redis/client/-/client-5.8.0.tgz", "integrity": "sha512-ywZjKGoSSAECGYOd9bJpws6d4867SN686obUWT/sRmo1c/Q8V+jWyInvlqwKa0BOvTHHwYeB2WFUEvd6PADeOQ==", + "peer": true, "requires": { "cluster-key-slot": "1.1.2" } @@ -24262,8 +23933,7 @@ "@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "peer": true + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" }, "@sinonjs/commons": { "version": "3.0.1", @@ -24377,7 +24047,6 @@ "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", - "peer": true, "requires": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -24390,7 +24059,6 @@ "version": "7.27.0", "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "peer": true, "requires": { "@babel/types": "^7.0.0" } @@ -24399,7 +24067,6 @@ "version": "7.4.4", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "peer": true, "requires": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -24409,7 +24076,6 @@ "version": "7.20.7", "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.7.tgz", "integrity": "sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==", - "peer": true, "requires": { "@babel/types": "^7.20.7" } @@ -24531,7 +24197,6 @@ "version": "4.1.9", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", - "peer": true, "requires": { "@types/node": "*" } @@ -24557,7 +24222,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "peer": true, "requires": { "@types/istanbul-lib-coverage": "*" } @@ -24566,7 +24230,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "peer": true, "requires": { "@types/istanbul-lib-report": "*" } @@ -24649,6 +24312,7 @@ "version": "24.9.1", "resolved": "https://registry.npmjs.org/@types/node/-/node-24.9.1.tgz", "integrity": "sha512-QoiaXANRkSXK6p0Duvt56W208du4P9Uye9hWLWgGMDTEoKPhuenzNcC4vGUmrNkiOKTlIrBoyNQYNpSwfEZXSg==", + "peer": true, "requires": { "undici-types": "~7.16.0" }, @@ -24732,8 +24396,7 @@ "@types/stack-utils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "peer": true + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, "@types/uuid": { "version": "10.0.0", @@ -24745,7 +24408,6 @@ "version": "17.0.33", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "peer": true, "requires": { "@types/yargs-parser": "*" } @@ -24753,8 +24415,7 @@ "@types/yargs-parser": { "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "peer": true + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==" }, "@types/yauzl": { "version": "2.10.3", @@ -24796,6 +24457,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.46.2.tgz", "integrity": "sha512-BnOroVl1SgrPLywqxyqdJ4l3S2MsKVLDVxZvjI1Eoe8ev2r3kGDo+PcMihNmDE+6/KjkTubSJnmqGZZjQSBq/g==", "dev": true, + "peer": true, "requires": { "@typescript-eslint/scope-manager": "8.46.2", "@typescript-eslint/types": "8.46.2", @@ -24969,7 +24631,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "peer": true, "requires": { "event-target-shim": "^5.0.0" } @@ -24986,7 +24647,8 @@ "acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==" + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "peer": true }, "acorn-jsx": { "version": "5.3.2", @@ -25066,8 +24728,7 @@ "anser": { "version": "1.4.10", "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", - "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", - "peer": true + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==" }, "ansi-colors": { "version": "4.1.3", @@ -25091,7 +24752,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "peer": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -25154,8 +24814,7 @@ "asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "peer": true + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "asn1": { "version": "0.2.6", @@ -25180,8 +24839,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "peer": true + "dev": true }, "async": { "version": "3.2.6", @@ -25191,8 +24849,15 @@ "async-limiter": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "peer": true + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "async-mutex": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz", + "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==", + "requires": { + "tslib": "^2.4.0" + } }, "asynckit": { "version": "0.4.0", @@ -25208,6 +24873,7 @@ "version": "1.12.2", "resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz", "integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==", + "peer": true, "requires": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", @@ -25228,7 +24894,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", - "peer": true, "requires": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -25243,7 +24908,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -25252,7 +24916,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -25262,7 +24925,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -25270,20 +24932,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -25294,7 +24953,6 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "peer": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -25307,7 +24965,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "peer": true, "requires": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -25322,7 +24979,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", - "peer": true, "requires": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -25334,7 +24990,6 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz", "integrity": "sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==", - "peer": true, "requires": { "hermes-parser": "0.25.1" } @@ -25343,7 +24998,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", - "peer": true, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -25366,7 +25020,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", - "peer": true, "requires": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -25530,7 +25183,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "peer": true, "requires": { "node-int64": "^0.4.0" } @@ -25777,7 +25429,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", - "peer": true, "requires": { "callsites": "^2.0.0" }, @@ -25785,8 +25436,7 @@ "callsites": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", - "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", - "peer": true + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==" } } }, @@ -25794,7 +25444,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", - "peer": true, "requires": { "caller-callsite": "^2.0.0" } @@ -25822,8 +25471,7 @@ "caniuse-lite": { "version": "1.0.30001716", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001716.tgz", - "integrity": "sha512-49/c1+x3Kwz7ZIWt+4DvK3aMJy9oYXXG6/97JKsnjdCk/6n9vVyWL8NAwVt95Lwt9eigI10Hl782kDfZUUlRXw==", - "peer": true + "integrity": "sha512-49/c1+x3Kwz7ZIWt+4DvK3aMJy9oYXXG6/97JKsnjdCk/6n9vVyWL8NAwVt95Lwt9eigI10Hl782kDfZUUlRXw==" }, "chai": { "version": "4.5.0", @@ -25846,7 +25494,6 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, - "peer": true, "requires": { "get-func-name": "^2.0.2" } @@ -25855,8 +25502,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "peer": true + "dev": true } } }, @@ -25923,7 +25569,6 @@ "version": "0.15.2", "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", - "peer": true, "requires": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -25934,8 +25579,7 @@ "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "peer": true + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" } } }, @@ -25943,7 +25587,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", - "peer": true, "requires": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -25956,14 +25599,12 @@ "escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "peer": true + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "peer": true + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" } } }, @@ -26200,7 +25841,6 @@ "version": "3.7.0", "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", - "peer": true, "requires": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -26212,7 +25852,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "peer": true, "requires": { "ms": "2.0.0" } @@ -26220,8 +25859,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -26451,7 +26089,6 @@ "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, - "peer": true, "requires": { "type-detect": "^4.0.0" } @@ -26637,8 +26274,7 @@ "electron-to-chromium": { "version": "1.5.145", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.145.tgz", - "integrity": "sha512-pZ5EcTWRq/055MvSBgoFEyKf2i4apwfoqJbK/ak2jnFq8oHjZ+vzc3AhRcz37Xn+ZJfL58R666FLJx0YOK9yTw==", - "peer": true + "integrity": "sha512-pZ5EcTWRq/055MvSBgoFEyKf2i4apwfoqJbK/ak2jnFq8oHjZ+vzc3AhRcz37Xn+ZJfL58R666FLJx0YOK9yTw==" }, "elliptic": { "version": "6.6.1", @@ -26750,7 +26386,6 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", - "peer": true, "requires": { "stackframe": "^1.3.4" } @@ -26804,6 +26439,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.34.0.tgz", "integrity": "sha512-RNCHRX5EwdrESy3Jc9o8ie8Bog+PeYvvSR8sDGoZxNFTvZ4dlxUB3WzQ3bQMztFrSRODGrLLj8g6OFuGY/aiQg==", "dev": true, + "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -27070,8 +26706,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "peer": true + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" }, "ethers": { "version": "6.15.0", @@ -27119,8 +26754,7 @@ "event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "peer": true + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, "eventemitter3": { "version": "4.0.7", @@ -27246,7 +26880,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "peer": true, "requires": { "bser": "2.1.1" } @@ -27321,7 +26954,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", - "peer": true, "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -27336,7 +26968,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "peer": true, "requires": { "ms": "2.0.0" } @@ -27344,14 +26975,12 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "peer": true, "requires": { "ee-first": "1.1.1" } @@ -27417,8 +27046,7 @@ "flow-enums-runtime": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", - "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", - "peer": true + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==" }, "follow-redirects": { "version": "1.15.6", @@ -27526,6 +27154,12 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, "function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -27534,8 +27168,7 @@ "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "peer": true + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" }, "get-caller-file": { "version": "2.0.5", @@ -27552,8 +27185,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "peer": true + "dev": true }, "get-intrinsic": { "version": "1.2.7", @@ -27575,8 +27207,7 @@ "get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "peer": true + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" }, "get-pkg-repo": { "version": "4.2.1", @@ -27884,14 +27515,12 @@ "hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", - "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "peer": true + "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==" }, "hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "peer": true, "requires": { "hermes-estree": "0.25.1" } @@ -28029,7 +27658,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", - "peer": true, "requires": { "queue": "6.0.2" } @@ -28124,7 +27752,6 @@ "version": "2.2.4", "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "peer": true, "requires": { "loose-envify": "^1.0.0" } @@ -28164,8 +27791,7 @@ "is-directory": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", - "peer": true + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==" }, "is-docker": { "version": "2.2.1", @@ -28458,7 +28084,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", - "peer": true, "requires": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -28471,14 +28096,12 @@ "jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "peer": true + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==" }, "jest-haste-map": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", - "peer": true, "requires": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -28498,7 +28121,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "peer": true, "requires": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -28515,7 +28137,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -28524,7 +28145,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -28534,7 +28154,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -28542,20 +28161,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -28566,7 +28182,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", - "peer": true, "requires": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -28576,14 +28191,12 @@ "jest-regex-util": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", - "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", - "peer": true + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==" }, "jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "peer": true, "requires": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -28597,7 +28210,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -28606,7 +28218,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -28616,7 +28227,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -28624,20 +28234,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -28648,7 +28255,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", - "peer": true, "requires": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -28662,7 +28268,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -28670,14 +28275,12 @@ "camelcase": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "peer": true + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==" }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -28687,7 +28290,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -28695,26 +28297,22 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "leven": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "peer": true + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -28725,7 +28323,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", - "peer": true, "requires": { "@types/node": "*", "jest-util": "^29.7.0", @@ -28736,14 +28333,12 @@ "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -28781,14 +28376,12 @@ "jsc-safe-url": { "version": "0.2.4", "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", - "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", - "peer": true + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==" }, "jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "peer": true + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==" }, "json-bigint": { "version": "1.0.0", @@ -29434,7 +29027,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", - "peer": true, "requires": { "debug": "^2.6.9", "marky": "^1.2.2" @@ -29444,7 +29036,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "peer": true, "requires": { "ms": "2.0.0" } @@ -29452,8 +29043,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -29624,8 +29214,7 @@ "lodash.throttle": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", - "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", - "peer": true + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==" }, "log-symbols": { "version": "4.1.0", @@ -29816,7 +29405,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "peer": true, "requires": { "js-tokens": "^3.0.0 || ^4.0.0" } @@ -29826,7 +29414,6 @@ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, - "peer": true, "requires": { "get-func-name": "^2.0.1" } @@ -29842,7 +29429,7 @@ "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", "dev": true, "requires": { - "semver": "^7.5.3" + "semver": "^6.0.0" } }, "make-error": { @@ -29946,7 +29533,6 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "peer": true, "requires": { "tmpl": "1.0.5" } @@ -29959,8 +29545,7 @@ "marky": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", - "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", - "peer": true + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==" }, "math-intrinsics": { "version": "1.1.0", @@ -29994,8 +29579,7 @@ "memoize-one": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", - "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", - "peer": true + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" }, "meow": { "version": "8.1.2", @@ -30126,7 +29710,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro/-/metro-0.82.2.tgz", "integrity": "sha512-hOBd4O4Cn/tLf3jz7IjSgD/A66MqMzgZuyF1I/pmNwYcY3q3j2vbh7Fa09KIbvUq5Yz7BewU356XboaEtEXPgA==", - "peer": true, "requires": { "@babel/code-frame": "^7.24.7", "@babel/core": "^7.25.2", @@ -30174,7 +29757,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -30183,7 +29765,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -30192,14 +29773,12 @@ "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "peer": true + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -30207,26 +29786,22 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "hermes-estree": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.28.1.tgz", - "integrity": "sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==", - "peer": true + "integrity": "sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==" }, "hermes-parser": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.28.1.tgz", "integrity": "sha512-nf8o+hE8g7UJWParnccljHumE9Vlq8F7MqIdeahl+4x0tvCUJYRrT0L7h0MMg/X9YJmkNwsfbaNNrzPtFXOscg==", - "peer": true, "requires": { "hermes-estree": "0.28.1" } @@ -30234,14 +29809,12 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "peer": true + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -30250,7 +29823,6 @@ "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "peer": true, "requires": {} } } @@ -30259,7 +29831,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.82.2.tgz", "integrity": "sha512-c2gesA7/B4dovPmmYC2HziNXb4XFG3YkQ9FjEzwRnR6KH2hT7nJn6mkcri1h85r3sMttpnmoBuZ8WDz980Zhlw==", - "peer": true, "requires": { "@babel/core": "^7.25.2", "flow-enums-runtime": "^0.0.6", @@ -30270,14 +29841,12 @@ "hermes-estree": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.28.1.tgz", - "integrity": "sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==", - "peer": true + "integrity": "sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==" }, "hermes-parser": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.28.1.tgz", "integrity": "sha512-nf8o+hE8g7UJWParnccljHumE9Vlq8F7MqIdeahl+4x0tvCUJYRrT0L7h0MMg/X9YJmkNwsfbaNNrzPtFXOscg==", - "peer": true, "requires": { "hermes-estree": "0.28.1" } @@ -30288,7 +29857,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.82.2.tgz", "integrity": "sha512-MxY4xvPKuE68NYpKJjH8YvVVugDL2QcuTracHsV5/30ZIaRr0v1QuAX5vt45OCQDQQWeh1rDv3E4JB6AbIvnZQ==", - "peer": true, "requires": { "exponential-backoff": "^3.1.1", "flow-enums-runtime": "^0.0.6", @@ -30300,7 +29868,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.82.2.tgz", "integrity": "sha512-lfjC9zzSri+rS7lkoCh04LniFga8JQVUqSuscD9KraIm9zRzwIwvaMx8V6Oogiezs+FAJUOSnVNhHcHc9l8H2Q==", - "peer": true, "requires": { "flow-enums-runtime": "^0.0.6" } @@ -30309,7 +29876,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.82.2.tgz", "integrity": "sha512-0dG3qCFLoE3ddNexAxSLJ7FbGjEbwUjDNOgYeCLoPSkKB01k5itvvr2HFfl2HisOCfLcpjpVzF5NtB/O71lxfA==", - "peer": true, "requires": { "connect": "^3.6.5", "cosmiconfig": "^5.0.5", @@ -30325,7 +29891,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "peer": true, "requires": { "sprintf-js": "~1.0.2" } @@ -30334,7 +29899,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", - "peer": true, "requires": { "import-fresh": "^2.0.0", "is-directory": "^0.3.1", @@ -30346,7 +29910,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", - "peer": true, "requires": { "caller-path": "^2.0.0", "resolve-from": "^3.0.0" @@ -30356,7 +29919,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "peer": true, "requires": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -30366,7 +29928,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", - "peer": true, "requires": { "error-ex": "^1.3.1", "json-parse-better-errors": "^1.0.1" @@ -30375,8 +29936,7 @@ "resolve-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", - "peer": true + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==" } } }, @@ -30384,7 +29944,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.82.2.tgz", "integrity": "sha512-d2XMkWbRh6PdPV1OZ8OyUyDWrtEbQ1m5ASpKtemLPbujfoE4RlwFZdl4ljfBNVVZ1s0z7tgsSFwKMyTeXgjtSg==", - "peer": true, "requires": { "flow-enums-runtime": "^0.0.6", "lodash.throttle": "^4.1.1", @@ -30395,7 +29954,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.82.2.tgz", "integrity": "sha512-pax0WA80eRH096YO0kwox+ZD5im3V0Vswr2x1YqdMcZVWlr6uwXgQdo9q+mpcvJ1k77J+hmY5HIg71bqrUptVg==", - "peer": true, "requires": { "debug": "^4.4.0", "fb-watchman": "^2.0.0", @@ -30412,7 +29970,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.82.2.tgz", "integrity": "sha512-+nveaEdQUvsoi0OSr4Cp+btevZsg2DKsu8kUJsvyLIcRRFPUw9CwzF3V2cA5b55DY5LcIJyAcZf4D9ARKfoilQ==", - "peer": true, "requires": { "flow-enums-runtime": "^0.0.6", "terser": "^5.15.0" @@ -30422,7 +29979,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.82.2.tgz", "integrity": "sha512-Who2hGzq2aCGSsBaQBU0L3SADiy/kj/gv0coujNWziRY4SKq7ECKzWqtVk1JlEF7IGXDDRDxEgFuLmPV6mZGVQ==", - "peer": true, "requires": { "flow-enums-runtime": "^0.0.6" } @@ -30431,7 +29987,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.82.2.tgz", "integrity": "sha512-gEcb2AfDs3GRs2SFjtEmG0k61B/cZEVCbh6cSmkjJpyHr+VRjw77MnDpX9AUcJYa4bCT63E7IEySOMM0Z8p87g==", - "peer": true, "requires": { "@babel/runtime": "^7.25.0", "flow-enums-runtime": "^0.0.6" @@ -30441,7 +29996,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.82.2.tgz", "integrity": "sha512-S26xPdz1/EeAY0HqaPXfny8CeiY0Dvl4sBLQiXGXhoES4gUDAuMhA1tioKrv5F+x68Sod8cp8Js6EGqbMXeqMA==", - "peer": true, "requires": { "@babel/traverse": "^7.25.3", "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", @@ -30458,8 +30012,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "peer": true + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" } } }, @@ -30467,7 +30020,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.82.2.tgz", "integrity": "sha512-iheanMnOMned6gjt6sKSfU5AoNyV6pJyQAWydwuHcjhGpa/kiAM0kKmw23qHejELK89Yw8HDZ3Fd/5l1jxpFVA==", - "peer": true, "requires": { "flow-enums-runtime": "^0.0.6", "invariant": "^2.2.4", @@ -30480,8 +30032,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "peer": true + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==" } } }, @@ -30489,7 +30040,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.82.2.tgz", "integrity": "sha512-kEveuEVxghTEXkDiyY0MT5QRqei092KJG46nduo0VghFgI6QFodbAjFit1ULyWsn2VOTGSUDJ3VgHBMy7MaccA==", - "peer": true, "requires": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", @@ -30503,7 +30053,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.82.2.tgz", "integrity": "sha512-MJQNz6cGjqewCRqFmPrsHu6Oe93v2B6zgHkrNxQ6XdPMJz5VHD33m8q+8UsNJOH8wUMoRu5JmYtuUTIVIFxh2A==", - "peer": true, "requires": { "@babel/core": "^7.25.2", "@babel/generator": "^7.25.0", @@ -30532,8 +30081,7 @@ "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "peer": true + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { "version": "1.52.0", @@ -30727,6 +30275,7 @@ "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.1.tgz", "integrity": "sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A==", "dev": true, + "peer": true, "requires": { "browser-stdout": "^1.3.1", "chokidar": "^4.0.1", @@ -31029,8 +30578,7 @@ "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "peer": true + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node-machine-id": { "version": "1.1.12", @@ -31040,8 +30588,7 @@ "node-releases": { "version": "2.0.19", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", - "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", - "peer": true + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==" }, "nopt": { "version": "8.1.0", @@ -31083,8 +30630,7 @@ "normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "peer": true + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" }, "npm-bundled": { "version": "4.0.0", @@ -31201,13 +30747,13 @@ "nullthrows": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", - "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", - "peer": true + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==" }, "nx": { "version": "21.6.6", "resolved": "https://registry.npmjs.org/nx/-/nx-21.6.6.tgz", "integrity": "sha512-KybewPwpU+8Vdqd6xwSh5sWlsXTGs9a2L7np+rsTTBQvNshNHl1R1nRExRB1L50od0wnnBm/5A2BB0jvO10IWw==", + "peer": true, "requires": { "@napi-rs/wasm-runtime": "0.2.4", "@nx/nx-darwin-arm64": "21.6.6", @@ -31326,7 +30872,6 @@ "version": "0.82.2", "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.82.2.tgz", "integrity": "sha512-sfUaYpjkAdHgu8cXLAyWXO98jW1EUOStTDNslfC9eb3tBLExe67PRqh09J0xdD6AlFKHFGTvXPbuHGvlrZNJNA==", - "peer": true, "requires": { "flow-enums-runtime": "^0.0.6" } @@ -31886,8 +31431,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "peer": true + "dev": true }, "pend": { "version": "1.2.0", @@ -32013,8 +31557,7 @@ "pirates": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "peer": true + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==" }, "pkg-dir": { "version": "4.2.0", @@ -32089,7 +31632,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "peer": true, "requires": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -32099,8 +31641,7 @@ "ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "peer": true + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==" } } }, @@ -32137,7 +31678,6 @@ "version": "8.3.0", "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", - "peer": true, "requires": { "asap": "~2.0.6" } @@ -32238,7 +31778,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", - "peer": true, "requires": { "inherits": "~2.0.3" } @@ -32271,8 +31810,7 @@ "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "peer": true + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { "version": "2.5.2", @@ -32314,7 +31852,6 @@ "version": "6.1.1", "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.1.tgz", "integrity": "sha512-TFo1MEnkqE6hzAbaztnyR5uLTMoz6wnEWwWBsCUzNt+sVXJycuRJdDqvL078M4/h65BI/YO5XWTaxZDWVsW0fw==", - "peer": true, "requires": { "shell-quote": "^1.6.1", "ws": "^7" @@ -32324,7 +31861,6 @@ "version": "7.5.10", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", - "peer": true, "requires": {} } } @@ -32382,7 +31918,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "peer": true, "requires": { "color-convert": "^2.0.1" } @@ -32391,7 +31926,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "peer": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -32401,7 +31935,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "peer": true, "requires": { "color-name": "~1.1.4" } @@ -32409,32 +31942,27 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "peer": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "commander": { "version": "12.1.0", "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "peer": true + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "peer": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "regenerator-runtime": { "version": "0.13.11", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "peer": true + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "peer": true, "requires": { "has-flag": "^4.0.0" } @@ -32443,7 +31971,6 @@ "version": "6.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", - "peer": true, "requires": { "async-limiter": "~1.0.0" } @@ -32461,8 +31988,7 @@ "react-refresh": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", - "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", - "peer": true + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==" }, "read": { "version": "4.1.0", @@ -32743,8 +32269,7 @@ "regenerator-runtime": { "version": "0.14.1", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "peer": true + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" }, "replace": { "version": "1.2.2", @@ -32997,8 +32522,7 @@ "scheduler": { "version": "0.25.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz", - "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==", - "peer": true + "integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==" }, "secure-json-parse": { "version": "2.7.0", @@ -33027,7 +32551,6 @@ "version": "0.19.0", "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "peer": true, "requires": { "debug": "2.6.9", "depd": "2.0.0", @@ -33048,7 +32571,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "peer": true, "requires": { "ms": "2.0.0" }, @@ -33056,8 +32578,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "peer": true + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" } } }, @@ -33065,7 +32586,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "peer": true, "requires": { "depd": "2.0.0", "inherits": "2.0.4", @@ -33077,16 +32597,14 @@ "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "peer": true + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" } } }, "serialize-error": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", - "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", - "peer": true + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==" }, "serialize-javascript": { "version": "6.0.2", @@ -33101,7 +32619,6 @@ "version": "1.16.2", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", - "peer": true, "requires": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -33112,8 +32629,7 @@ "encodeurl": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "peer": true + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" } } }, @@ -33143,8 +32659,7 @@ "shell-quote": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.2.tgz", - "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==", - "peer": true + "integrity": "sha512-AzqKpGKjrj7EM6rKVQEPpB288oCfnrEIuyoT9cyF4nmGa7V8Zk6f7RRqYisX8X9m+Q7bd632aZW4ky7EhbQztA==" }, "side-channel": { "version": "1.0.4", @@ -33282,7 +32797,6 @@ "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "peer": true, "requires": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -33379,7 +32893,6 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "peer": true, "requires": { "escape-string-regexp": "^2.0.0" }, @@ -33387,22 +32900,19 @@ "escape-string-regexp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "peer": true + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" } } }, "stackframe": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", - "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", - "peer": true + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==" }, "stacktrace-parser": { "version": "0.1.11", "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", - "peer": true, "requires": { "type-fest": "^0.7.1" }, @@ -33410,8 +32920,7 @@ "type-fest": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", - "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", - "peer": true + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==" } } }, @@ -33609,7 +33118,6 @@ "version": "5.39.0", "resolved": "https://registry.npmjs.org/terser/-/terser-5.39.0.tgz", "integrity": "sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==", - "peer": true, "requires": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.8.2", @@ -33620,8 +33128,7 @@ "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "peer": true + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" } } }, @@ -33629,7 +33136,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "peer": true, "requires": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -33652,8 +33158,7 @@ "throat": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", - "peer": true + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==" }, "through": { "version": "2.3.8", @@ -33716,7 +33221,8 @@ "picomatch": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==" + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "peer": true } } }, @@ -33731,8 +33237,7 @@ "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "peer": true + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==" }, "to-regex-range": { "version": "5.0.1", @@ -33804,6 +33309,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "peer": true, "requires": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -33953,7 +33459,8 @@ "typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", - "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==" + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "peer": true }, "uglify-js": { "version": "3.19.3", @@ -34006,7 +33513,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", - "peer": true, "requires": { "escalade": "^3.2.0", "picocolors": "^1.1.1" @@ -34042,8 +33548,7 @@ "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "peer": true + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" }, "uuid": { "version": "13.0.0", @@ -34089,8 +33594,7 @@ "vlq": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", - "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", - "peer": true + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==" }, "walk-up-path": { "version": "4.0.0", @@ -34101,7 +33605,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "peer": true, "requires": { "makeerror": "1.0.12" } diff --git a/packages/config-service/src/services/globalConfig.ts b/packages/config-service/src/services/globalConfig.ts index 346cae7998..a92e33a874 100644 --- a/packages/config-service/src/services/globalConfig.ts +++ b/packages/config-service/src/services/globalConfig.ts @@ -363,6 +363,11 @@ const _CONFIG = { required: false, defaultValue: null, }, + LOCAL_LOCK_MAX_ENTRIES: { + type: 'number', + required: false, + defaultValue: 1000, + }, LOG_LEVEL: { type: 'string', required: false, @@ -649,6 +654,21 @@ const _CONFIG = { required: false, defaultValue: true, }, + LOCK_MAX_HOLD_MS: { + type: 'number', + required: false, + defaultValue: 30000, + }, + LOCK_QUEUE_POLL_INTERVAL_MS: { + type: 'number', + required: false, + defaultValue: 50, + }, + ENABLE_NONCE_ORDERING: { + type: 'boolean', + required: false, + defaultValue: false, + }, USE_MIRROR_NODE_MODULARIZED_SERVICES: { type: 'boolean', required: false, diff --git a/packages/relay/package.json b/packages/relay/package.json index aa95777f4c..424a28d5fc 100644 --- a/packages/relay/package.json +++ b/packages/relay/package.json @@ -53,6 +53,7 @@ "dependencies": { "@hashgraph/json-rpc-config-service": "file:../config-service", "@hashgraph/sdk": "^2.63.0", + "async-mutex": "^0.5.0", "axios": "^1.4.0", "axios-retry": "^4.5.0", "better-lookup": "^1.3.0", diff --git a/packages/relay/src/lib/eth.ts b/packages/relay/src/lib/eth.ts index 53e13cc66f..f358c90bc6 100644 --- a/packages/relay/src/lib/eth.ts +++ b/packages/relay/src/lib/eth.ts @@ -19,6 +19,7 @@ import { IBlockService, ICommonService, IContractService, + LockService, TransactionPoolService, TransactionService, } from './services'; @@ -126,6 +127,7 @@ export class EthImpl implements Eth { chain: string, public readonly cacheService: CacheService, storage: PendingTransactionStorage, + lockService: LockService, ) { this.chain = chain; this.logger = logger; @@ -146,6 +148,7 @@ export class EthImpl implements Eth { logger, mirrorNodeClient, transactionPoolService, + lockService, ); this.accountService = new AccountService( cacheService, diff --git a/packages/relay/src/lib/relay.ts b/packages/relay/src/lib/relay.ts index 2a250bed93..769c914ea4 100644 --- a/packages/relay/src/lib/relay.ts +++ b/packages/relay/src/lib/relay.ts @@ -20,6 +20,7 @@ import { DebugImpl } from './debug'; import { RpcMethodDispatcher } from './dispatcher'; import { EthImpl } from './eth'; import { NetImpl } from './net'; +import { LockService, LockStrategyFactory } from './services'; import { CacheService } from './services/cacheService/cacheService'; import HAPIService from './services/hapiService/hapiService'; import { HbarLimitService } from './services/hbarLimitService'; @@ -314,7 +315,7 @@ export class Relay { duration, ); - // Create HAPI service + const lockService = new LockService(LockStrategyFactory.create(this.redisClient, this.logger)); const hapiService = new HAPIService(this.logger, this.register, hbarLimitService); this.operatorAccountId = hapiService.getOperatorAccountId(); @@ -348,6 +349,7 @@ export class Relay { chainId, this.cacheService, storage, + lockService, ); // Set up event listeners diff --git a/packages/relay/src/lib/services/ethService/transactionService/TransactionService.ts b/packages/relay/src/lib/services/ethService/transactionService/TransactionService.ts index b44d810d3d..fa44d59cb3 100644 --- a/packages/relay/src/lib/services/ethService/transactionService/TransactionService.ts +++ b/packages/relay/src/lib/services/ethService/transactionService/TransactionService.ts @@ -21,7 +21,7 @@ import { Precheck } from '../../../precheck'; import { ITransactionReceipt, RequestDetails, TypedEvents } from '../../../types'; import { CacheService } from '../../cacheService/cacheService'; import HAPIService from '../../hapiService/hapiService'; -import { ICommonService, TransactionPoolService } from '../../index'; +import { ICommonService, LockService, TransactionPoolService } from '../../index'; import { ITransactionService } from './ITransactionService'; export class TransactionService implements ITransactionService { @@ -46,6 +46,13 @@ export class TransactionService implements ITransactionService { */ private readonly hapiService: HAPIService; + /** + * The lock service for managing transaction ordering. + * @private + * @readonly + */ + private readonly lockService: LockService; + /** * Logger instance for logging messages. * @private @@ -86,6 +93,7 @@ export class TransactionService implements ITransactionService { logger: Logger, mirrorNodeClient: MirrorNodeClient, transactionPoolService: TransactionPoolService, + lockService: LockService, ) { this.cacheService = cacheService; this.chain = chain; @@ -96,6 +104,7 @@ export class TransactionService implements ITransactionService { this.mirrorNodeClient = mirrorNodeClient; this.precheck = new Precheck(mirrorNodeClient, chain, transactionPoolService); this.transactionPoolService = transactionPoolService; + this.lockService = lockService; } /** @@ -253,36 +262,60 @@ export class TransactionService implements ITransactionService { const transactionBuffer = Buffer.from(this.prune0x(transaction), 'hex'); const parsedTx = Precheck.parseRawTransaction(transaction); - const networkGasPriceInWeiBars = Utils.addPercentageBufferToGasPrice( - await this.common.getGasPriceInWeibars(requestDetails), - ); + let lockSessionKey: string | undefined; + + // Acquire lock FIRST - before any side effects or async operations + // This ensures proper nonce ordering for transactions from the same sender + if (parsedTx.from) { + lockSessionKey = await this.lockService.acquireLock(parsedTx.from); + } - await this.validateRawTransaction(parsedTx, networkGasPriceInWeiBars, requestDetails); + try { + const networkGasPriceInWeiBars = Utils.addPercentageBufferToGasPrice( + await this.common.getGasPriceInWeibars(requestDetails), + ); - // Save the transaction to the transaction pool before submitting it to the network - await this.transactionPoolService.saveTransaction(parsedTx.from!, parsedTx); + await this.validateRawTransaction(parsedTx, networkGasPriceInWeiBars, requestDetails); - /** - * Note: If the USE_ASYNC_TX_PROCESSING feature flag is enabled, - * the transaction hash is calculated and returned immediately after passing all prechecks. - * All transaction processing logic is then handled asynchronously in the background. - */ - const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING'); - if (useAsyncTxProcessing) { - this.sendRawTransactionProcessor(transactionBuffer, parsedTx, networkGasPriceInWeiBars, requestDetails); - return Utils.computeTransactionHash(transactionBuffer); - } + // Save the transaction to the transaction pool before submitting it to the network + await this.transactionPoolService.saveTransaction(parsedTx.from!, parsedTx); - /** - * Note: If the USE_ASYNC_TX_PROCESSING feature flag is disabled, - * wait for all transaction processing logic to complete before returning the transaction hash. - */ - return await this.sendRawTransactionProcessor( - transactionBuffer, - parsedTx, - networkGasPriceInWeiBars, - requestDetails, - ); + /** + * Note: If the USE_ASYNC_TX_PROCESSING feature flag is enabled, + * the transaction hash is calculated and returned immediately after passing all prechecks. + * All transaction processing logic is then handled asynchronously in the background. + */ + const useAsyncTxProcessing = ConfigService.get('USE_ASYNC_TX_PROCESSING'); + if (useAsyncTxProcessing) { + // Fire and forget - lock will be released after consensus submission + this.sendRawTransactionProcessor( + transactionBuffer, + parsedTx, + networkGasPriceInWeiBars, + lockSessionKey, + requestDetails, + ); + return Utils.computeTransactionHash(transactionBuffer); + } + + /** + * Note: If the USE_ASYNC_TX_PROCESSING feature flag is disabled, + * wait for all transaction processing logic to complete before returning the transaction hash. + */ + return await this.sendRawTransactionProcessor( + transactionBuffer, + parsedTx, + networkGasPriceInWeiBars, + lockSessionKey, + requestDetails, + ); + } catch (error) { + // Release lock on any error during validation or prechecks + if (lockSessionKey) { + await this.lockService.releaseLock(parsedTx.from!, lockSessionKey); + } + throw error; + } } /** @@ -472,12 +505,14 @@ export class TransactionService implements ITransactionService { * @param {EthersTransaction} parsedTx - The parsed Ethereum transaction object. * @param {number} networkGasPriceInWeiBars - The current network gas price in wei bars. * @param {RequestDetails} requestDetails - Details of the request for logging and tracking purposes. + * @param {string | null} lockSessionKey - The session key for the acquired lock, null if no lock was acquired. * @returns {Promise} A promise that resolves to the transaction hash if successful, or a JsonRpcError if an error occurs. */ async sendRawTransactionProcessor( transactionBuffer: Buffer, parsedTx: EthersTransaction, networkGasPriceInWeiBars: number, + lockSessionKey: string | undefined, requestDetails: RequestDetails, ): Promise { let sendRawTransactionError: any; @@ -495,6 +530,9 @@ export class TransactionService implements ITransactionService { requestDetails, ); + if (lockSessionKey) { + await this.lockService.releaseLock(originalCallerAddress, lockSessionKey); + } // Remove the transaction from the transaction pool after submission await this.transactionPoolService.removeTransaction(originalCallerAddress, parsedTx.serialized); diff --git a/packages/relay/src/lib/services/index.ts b/packages/relay/src/lib/services/index.ts index 05d358f89e..e2570ea6d8 100644 --- a/packages/relay/src/lib/services/index.ts +++ b/packages/relay/src/lib/services/index.ts @@ -17,3 +17,5 @@ export * from './rateLimiterService/RedisRateLimitStore'; export * from './rateLimiterService/rateLimiterService'; export * from './transactionPoolService/LocalPendingTransactionStorage'; export * from './transactionPoolService/transactionPoolService'; +export * from './lockService/LockService'; +export * from './lockService/LockStrategyFactory'; diff --git a/packages/relay/src/lib/services/lockService/LocalLockStrategy.ts b/packages/relay/src/lib/services/lockService/LocalLockStrategy.ts new file mode 100644 index 0000000000..6a6c189822 --- /dev/null +++ b/packages/relay/src/lib/services/lockService/LocalLockStrategy.ts @@ -0,0 +1,162 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { Mutex } from 'async-mutex'; +import { randomUUID } from 'crypto'; +import { LRUCache } from 'lru-cache'; +import { Logger } from 'pino'; + +import { LockStrategy } from '../../types/lock'; +import { LockService } from './LockService'; + +/** + * Represents the internal state for a lock associated with a given address. + */ +export interface LockState { + mutex: Mutex; + sessionKey: string | null; + acquiredAt: number | null; + lockTimeoutId: NodeJS.Timeout | null; +} + +/** + * Implements a local, in-memory locking strategy. + * + * Each unique "address" gets its own mutex to ensure only one session can hold + * the lock at a time. Locks are auto-expiring and stored in an LRU cache. + */ +export class LocalLockStrategy implements LockStrategy { + /** + * LRU cache of lock states, keyed by address. + */ + private localLockStates = new LRUCache({ + max: ConfigService.get('LOCAL_LOCK_MAX_ENTRIES'), + }); + + /** + * Logger. + * + * @private + */ + private readonly logger: Logger; + + /** + * Creates a new LocalLockStrategy instance. + * + * @param logger - The logger + */ + constructor(logger: Logger) { + this.logger = logger; + } + + /** + * Acquire a lock for a specific address. + * Waits until the lock is available (blocking if another session holds it). + * + * @param address - The key representing the resource to lock + * @returns A session key identifying the current lock owner + */ + async acquireLock(address: string): Promise { + const sessionKey = randomUUID(); + if (this.logger.isLevelEnabled('debug')) { + this.logger.debug(`Acquiring lock for address ${address} and sessionkey ${sessionKey}.`); + } + const state = this.getOrCreateState(address); + + // Acquire the mutex (this will block until available) + await state.mutex.acquire(); + + // Record lock ownership metadata + state.sessionKey = sessionKey; + state.acquiredAt = Date.now(); + + // Start a 30-second timer to auto-release if lock not manually released + state.lockTimeoutId = setTimeout(() => { + this.forceReleaseExpiredLock(address, sessionKey); + }, ConfigService.get('LOCK_MAX_HOLD_MS')); + + return sessionKey; + } + + /** + * Release a previously acquired lock, if the session key matches the current owner. + * + * @param address - The locked resource key + * @param sessionKey - The session key of the lock holder + */ + async releaseLock(address: string, sessionKey: string): Promise { + const normalizedAddress = LockService.normalizeAddress(address); + const state = this.localLockStates.get(normalizedAddress); + if (state) { + // Ensure only the lock owner can release + if (state.sessionKey === sessionKey) { + await this.doRelease(state); + if (this.logger.isLevelEnabled('debug')) { + const holdTime = Date.now() - state.acquiredAt!; + this.logger.debug( + `Releasing lock for address ${address} and session key ${sessionKey} held for ${holdTime}ms.`, + ); + } + } + } + } + + /** + * Retrieve an existing lock state for the given address, or create a new one if it doesn't exist. + * + * @param address - Unique identifier for the lock + * @returns The LockState object associated with the address + */ + private getOrCreateState(address: string): LockState { + const normalizedAddress = LockService.normalizeAddress(address); + if (!this.localLockStates.has(normalizedAddress)) { + this.localLockStates.set(normalizedAddress, { + mutex: new Mutex(), + sessionKey: null, + acquiredAt: null, + lockTimeoutId: null, + }); + } + + return this.localLockStates.get(normalizedAddress)!; + } + + /** + * Internal helper to perform cleanup and release the mutex. + * + * @param state - The LockState instance to reset and release + */ + private async doRelease(state: LockState): Promise { + // Clear timeout first + clearTimeout(state.lockTimeoutId!); + + // Reset state + state.sessionKey = null; + state.lockTimeoutId = null; + state.acquiredAt = null; + + // Release the mutex lock + state.mutex.release(); + } + + /** + * Forcefully release a lock that has exceeded its maximum execution time. + * Used by the timeout set during `acquireLock`. + * + * @param address - The resource key associated with the lock + * @param sessionKey - The session key to verify ownership before releasing + */ + private async forceReleaseExpiredLock(address: string, sessionKey: string): Promise { + const normalizedAddress = LockService.normalizeAddress(address); + const state = this.localLockStates.get(normalizedAddress); + + if (state?.sessionKey === sessionKey) { + await this.doRelease(state); + + if (this.logger.isLevelEnabled('debug')) { + const holdTime = Date.now() - state.acquiredAt!; + this.logger.debug(`Force releasing expired local lock for address ${address} held for ${holdTime}ms.`); + } + } + } +} diff --git a/packages/relay/src/lib/services/lockService/LockService.ts b/packages/relay/src/lib/services/lockService/LockService.ts new file mode 100644 index 0000000000..59bf2d9311 --- /dev/null +++ b/packages/relay/src/lib/services/lockService/LockService.ts @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; + +import { LockStrategy } from '../../types'; + +/** + * Service that manages transaction ordering through distributed locking. + * Uses a strategy pattern to support both local (in-memory) and distributed (Redis) locking. + */ +export class LockService { + /** + * The underlying lock strategy implementation (Local or Redis). + */ + private readonly strategy: LockStrategy; + + /** + * Creates a new LockService instance. + * + * @param strategy - The lock strategy implementation to use. + */ + constructor(strategy: LockStrategy) { + this.strategy = strategy; + } + + /** + * Acquires a lock for the specified address. + * Blocks until the lock is available (no timeout on waiting). + * + * @param address - The sender address to acquire the lock for. + * @returns A promise that resolves to a unique session key, or null if acquisition fails (fail open). + */ + async acquireLock(address: string): Promise { + if (ConfigService.get('ENABLE_NONCE_ORDERING')) { + return await this.strategy.acquireLock(address); + } + } + + /** + * Releases a lock for the specified address. + * Only succeeds if the session key matches the current lock holder. + * + * @param address - The sender address to release the lock for. + * @param sessionKey - The session key obtained during lock acquisition. + */ + async releaseLock(address: string, sessionKey: string): Promise { + if (ConfigService.get('ENABLE_NONCE_ORDERING')) { + await this.strategy.releaseLock(address, sessionKey); + } + } + + /** + * Normalizes an address to lowercase for consistent key generation across lock strategies. + * + * @param address - The address to normalize. + * @returns The normalized address. + */ + static normalizeAddress(address: string): string { + return address.toLowerCase(); + } +} diff --git a/packages/relay/src/lib/services/lockService/LockStrategyFactory.ts b/packages/relay/src/lib/services/lockService/LockStrategyFactory.ts new file mode 100644 index 0000000000..2a0082f9bb --- /dev/null +++ b/packages/relay/src/lib/services/lockService/LockStrategyFactory.ts @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { Logger } from 'pino'; +import { RedisClientType } from 'redis'; + +import { LockStrategy } from '../../types'; +import { LocalLockStrategy } from './LocalLockStrategy'; +import { RedisLockStrategy } from './RedisLockStrategy'; + +/** + * Factory for creating LockStrategy instances. + * + * Encapsulates the logic for selecting the appropriate lock strategy implementation + * based on available infrastructure (Redis vs in-memory). + */ +export class LockStrategyFactory { + /** + * Creates a LockStrategy instance. + * + * @param redisClient - Optional Redis client. If provided, creates Redis-backed lock strategy; + * otherwise creates local in-memory lock strategy. + * @param logger - Logger instance for the lock strategy. + * @returns A LockStrategy implementation. + */ + + static create(redisClient: RedisClientType | undefined, logger: Logger): LockStrategy { + if (redisClient) { + return new RedisLockStrategy(redisClient, logger.child({ name: 'redis-lock-strategy' })); + } + + return new LocalLockStrategy(logger.child({ name: 'local-lock-strategy' })); + } +} diff --git a/packages/relay/src/lib/services/lockService/RedisLockStrategy.ts b/packages/relay/src/lib/services/lockService/RedisLockStrategy.ts new file mode 100644 index 0000000000..dd51130e2a --- /dev/null +++ b/packages/relay/src/lib/services/lockService/RedisLockStrategy.ts @@ -0,0 +1,204 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { ConfigService } from '@hashgraph/json-rpc-config-service/dist/services'; +import { randomUUID } from 'crypto'; +import { Logger } from 'pino'; +import { RedisClientType } from 'redis'; + +import { LockStrategy } from '../../types/lock'; +import { LockService } from './LockService'; + +/** + * Redis-based distributed lock strategy implementing FIFO queue semantics. + * + * Uses Redis SET NX + LIST for distributed locking across multiple relay instances. + * Provides automatic TTL-based expiration and polling-based lock acquisition. + * + * @remarks + * - Lock keys: `{prefix}:{address}` stores current holder's session key + * - Queue keys: `{prefix}:queue:{address}` stores FIFO queue of waiters + * - TTL on lock keys provides automatic cleanup on crashes/hangs + */ +export class RedisLockStrategy implements LockStrategy { + private readonly redisClient: RedisClientType; + private readonly logger: Logger; + private readonly maxLockHoldMs: number; + private readonly pollIntervalMs: number; + private readonly keyPrefix = 'lock'; + + constructor(redisClient: RedisClientType, logger: Logger) { + this.redisClient = redisClient; + this.logger = logger; + this.maxLockHoldMs = ConfigService.get('LOCK_MAX_HOLD_MS'); + this.pollIntervalMs = ConfigService.get('LOCK_QUEUE_POLL_INTERVAL_MS'); + } + + /** + * Acquires a lock for the specified address using FIFO queue semantics. + * + * @param address - The sender address to acquire the lock for (will be normalized). + * @returns A promise that resolves to a unique session key upon successful acquisition, or null if acquisition fails (fail open). + */ + async acquireLock(address: string): Promise { + const sessionKey = this.generateSessionKey(); + const lockKey = this.getLockKey(address); + const queueKey = this.getQueueKey(address); + const startTime = Date.now(); + let joinedQueue = false; + + try { + // Join FIFO queue + await this.redisClient.lPush(queueKey, sessionKey); + joinedQueue = true; + + if (this.logger.isLevelEnabled('trace')) { + this.logger.trace(`Lock acquisition started: address=${address}, sessionKey=${sessionKey}`); + } + + // Poll until first in queue and can acquire lock + while (true) { + // Check if first in line + const firstInQueue = await this.redisClient.lIndex(queueKey, -1); + + if (firstInQueue === sessionKey) { + // Try to acquire lock with TTL + const acquired = await this.redisClient.set(lockKey, sessionKey, { + NX: true, // Only set if not exists + PX: this.maxLockHoldMs, // TTL in milliseconds + }); + + if (acquired) { + const acquisitionDuration = Date.now() - startTime; + const queueLength = await this.redisClient.lLen(queueKey); + + if (this.logger.isLevelEnabled('debug')) { + this.logger.debug( + `Lock acquired: address=${address}, sessionKey=${sessionKey}, duration=${acquisitionDuration}ms, queueLength=${queueLength}`, + ); + } + + return sessionKey; + } + } + + // Wait before checking again + await this.sleep(this.pollIntervalMs); + } + } catch (error) { + this.logger.error(error, `Failed to acquire lock: address=${address}, sessionKey=${sessionKey}. Failing open.`); + return; + } finally { + // Always remove from queue if we joined it (whether success or failure) + if (joinedQueue) { + await this.removeFromQueue(queueKey, sessionKey, address); + } + } + } + + /** + * Releases a lock for the specified address. + * Only succeeds if the session key matches the current lock holder. + * + * @param address - The sender address to release the lock for (will be normalized). + * @param sessionKey - The session key proving ownership of the lock. + */ + async releaseLock(address: string, sessionKey: string): Promise { + const lockKey = this.getLockKey(address); + + try { + // Atomic check-and-delete using Lua script + // Only deletes the lock if the session key matches (ownership check) + const result = await this.redisClient.eval( + ` + if redis.call("get", KEYS[1]) == ARGV[1] then + return redis.call("del", KEYS[1]) + else + return 0 + end + `, + { + keys: [lockKey], + arguments: [sessionKey], + }, + ); + + if (result === 1) { + if (this.logger.isLevelEnabled('debug')) { + this.logger.debug(`Lock released: address=${address}, sessionKey=${sessionKey}`); + } + } else { + // Lock was already released or owned by someone else - ignore + if (this.logger.isLevelEnabled('trace')) { + this.logger.trace( + `Lock release ignored (not owner or already released): address=${address}, sessionKey=${sessionKey}`, + ); + } + } + } catch (error) { + this.logger.error(error, `Failed to release lock: address=${address}, sessionKey=${sessionKey}`); + // Don't throw - release failures should not block the caller + } + } + + /** + * Generates the Redis key for a lock. + * Automatically normalizes the address to ensure consistency. + * + * @param address - The sender address (will be normalized to lowercase). + * @returns The Redis lock key. + */ + private getLockKey(address: string): string { + const normalizedAddress = LockService.normalizeAddress(address); + return `${this.keyPrefix}:${normalizedAddress}`; + } + + /** + * Generates the Redis key for a lock queue. + * Automatically normalizes the address to ensure consistency. + * + * @param address - The sender address (will be normalized to lowercase). + * @returns The Redis queue key. + */ + private getQueueKey(address: string): string { + const normalizedAddress = LockService.normalizeAddress(address); + return `${this.keyPrefix}:queue:${normalizedAddress}`; + } + + /** + * Removes a session key from the queue. + * Used for cleanup after successful acquisition or on error. + * + * @param queueKey - The queue key. + * @param sessionKey - The session key to remove. + * @param address - The address (for logging). + */ + private async removeFromQueue(queueKey: string, sessionKey: string, address: string): Promise { + try { + await this.redisClient.lRem(queueKey, 1, sessionKey); + if (this.logger.isLevelEnabled('trace')) { + this.logger.trace(`Removed from queue: address=${address}, sessionKey=${sessionKey}`); + } + } catch (error) { + this.logger.warn(error, `Failed to remove from queue: address=${address}, sessionKey=${sessionKey}`); + } + } + + /** + * Generates a unique session key for lock acquisition. + * Protected to allow test mocking. + * + * @returns A unique session key. + */ + protected generateSessionKey(): string { + return randomUUID(); + } + + /** + * Sleeps for the specified duration. + * + * @param ms - Duration in milliseconds. + */ + private sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)); + } +} diff --git a/packages/relay/src/lib/types/index.ts b/packages/relay/src/lib/types/index.ts index 5a0609f1fa..cd7c70a577 100644 --- a/packages/relay/src/lib/types/index.ts +++ b/packages/relay/src/lib/types/index.ts @@ -13,3 +13,4 @@ export * from './spendingPlanConfig'; export * from './registry'; export * from './debug'; export * from './rateLimiter'; +export * from './lock'; diff --git a/packages/relay/src/lib/types/lock.ts b/packages/relay/src/lib/types/lock.ts new file mode 100644 index 0000000000..ea3b7bacae --- /dev/null +++ b/packages/relay/src/lib/types/lock.ts @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: Apache-2.0 + +/** + * Interface for lock strategy implementations. + * Strategies handle the actual locking mechanism (local in-memory or distributed via Redis). + * + * @remarks + * Implementations must normalize addresses (e.g., lowercase) internally to ensure consistency. + */ +export interface LockStrategy { + /** + * Acquires a lock for the specified address. + * Blocks until the lock is available or timeout is reached. + * + * @param address - The address to acquire the lock for (will be normalized by implementation). + * @returns A promise that resolves to a unique session key upon successful acquisition, or null if acquisition fails (fail open). + */ + acquireLock(address: string): Promise; + + /** + * Releases a lock for the specified address. + * Only succeeds if the provided session key matches the current lock holder. + * + * @param address - The address to release the lock for (will be normalized by implementation). + * @param sessionKey - The session key proving ownership of the lock. + * @returns A promise that resolves when the lock is released or rejected if not owner. + */ + releaseLock(address: string, sessionKey: string): Promise; +} diff --git a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts index b208ffddef..64d6cb9450 100644 --- a/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts +++ b/packages/relay/tests/lib/eth/eth_sendRawTransaction.spec.ts @@ -23,7 +23,7 @@ import { formatTransactionIdWithoutQueryParams } from '../../../src/formatters'; import { SDKClient } from '../../../src/lib/clients'; import constants from '../../../src/lib/constants'; import { SDKClientError } from '../../../src/lib/errors/SDKClientError'; -import { TransactionPoolService } from '../../../src/lib/services'; +import { LockService, TransactionPoolService } from '../../../src/lib/services'; import { CacheService } from '../../../src/lib/services/cacheService/cacheService'; import HAPIService from '../../../src/lib/services/hapiService/hapiService'; import { HbarLimitService } from '../../../src/lib/services/hbarLimitService'; @@ -54,7 +54,7 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () } = generateEthTestEnv(); const requestDetails = new RequestDetails({ requestId: 'eth_sendRawTransactionTest', ipAddress: '0.0.0.0' }); - + let lockServiceStub: sinon.SinonStubbedInstance; overrideEnvsInMochaDescribe({ ETH_GET_TRANSACTION_COUNT_MAX_BLOCK_RANGE: 1 }); this.beforeEach(async () => { @@ -134,6 +134,11 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); JSON.stringify(restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES))); JSON.stringify(restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate))); + lockServiceStub = sinon.createStubInstance(LockService); + + // Replace the lock service with our stub + ethImpl['transactionService']['lockService'] = lockServiceStub; + lockServiceStub.acquireLock.resolves(); }); afterEach(() => { @@ -561,5 +566,345 @@ describe('@ethSendRawTransaction eth_sendRawTransaction spec', async function () }); }); }); + + describe('Lock Release Error Handling', () => { + let loggerErrorStub: sinon.SinonStub; + overrideEnvsInMochaDescribe({ ENABLE_NONCE_ORDERING: true }); + beforeEach(() => { + loggerErrorStub = sinon.stub(ethImpl['transactionService']['logger'], 'error'); + }); + + afterEach(() => { + loggerErrorStub.restore(); + }); + + describe('Validation Error Path', () => { + it('should preserve original validation error when lock release fails', async function () { + const transaction = { + chainId: Number(ConfigService.get('CHAIN_ID')), + to: ACCOUNT_ADDRESS_1, + from: accountAddress, + value: '0x1', + gasPrice: '0x1', // Too low - will fail validation + gasLimit: MAX_GAS_LIMIT_HEX, + nonce: 0, + }; + const signed = await signTransaction(transaction); + + // Mock account data + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + + // Simulate successful lock acquisition + lockServiceStub.acquireLock.resolves('test-session-key-123'); + + // Simulate lock release failure + lockServiceStub.releaseLock.resolves(); + + await expect(ethImpl.sendRawTransaction(signed, requestDetails)).to.be.rejectedWith( + "Value can't be non-zero and less than 10_000_000_000 wei which is 1 tinybar", + ); + + // Verify lock was acquired + sinon.assert.calledOnce(lockServiceStub.acquireLock); + sinon.assert.calledWith(lockServiceStub.acquireLock, accountAddress); + + // Verify lock release was attempted + sinon.assert.calledOnce(lockServiceStub.releaseLock); + sinon.assert.calledWith(lockServiceStub.releaseLock, accountAddress, 'test-session-key-123'); + }); + + it('should preserve original precheck error when lock release fails', async function () { + const transaction = { + chainId: Number(ConfigService.get('CHAIN_ID')), + to: ACCOUNT_ADDRESS_1, + from: accountAddress, + value: '0x2386f26fc10000', // Large value + gasPrice, + gasLimit: MAX_GAS_LIMIT_HEX, + nonce: 0, + }; + const signed = await signTransaction(transaction); + + // Mock insufficient balance + const poorAccount = { + ...ACCOUNT_RES, + balance: { balance: 1000 }, // Very low balance + }; + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(poorAccount)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + + lockServiceStub.acquireLock.resolves('test-session-key-456'); + lockServiceStub.releaseLock.resolves(); + + await expect(ethImpl.sendRawTransaction(signed, requestDetails)).to.be.rejectedWith( + JsonRpcError, + 'Insufficient funds', + ); + + // Verify lock was acquired + sinon.assert.calledOnce(lockServiceStub.acquireLock); + sinon.assert.calledWith(lockServiceStub.acquireLock, accountAddress); + + // Verify lock release was attempted despite failure + sinon.assert.calledOnce(lockServiceStub.releaseLock); + }); + + it('should successfully release lock when validation fails and lock service works', async function () { + const transaction = { + chainId: Number(ConfigService.get('CHAIN_ID')), + to: ACCOUNT_ADDRESS_1, + from: accountAddress, + value: '0x1', + gasPrice: '0x1', // Too low + gasLimit: MAX_GAS_LIMIT_HEX, + nonce: 0, + }; + const signed = await signTransaction(transaction); + + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + + lockServiceStub.acquireLock.resolves('test-session-key-success'); + lockServiceStub.releaseLock.resolves(); // Successful release + + await expect(ethImpl.sendRawTransaction(signed, requestDetails)).to.be.rejectedWith( + JsonRpcError, + "Value can't be non-zero and less than 10_000_000_000 wei which is 1 tinybar", + ); + // Verify lock was properly released + sinon.assert.calledOnce(lockServiceStub.releaseLock); + sinon.assert.calledWith(lockServiceStub.releaseLock, accountAddress, 'test-session-key-success'); + }); + }); + + describe('Successful Transaction Path', () => { + it('should acquire lock and pass lockSessionKey to processor without releasing', async function () { + const signed = await signTransaction(transaction); + + // Mock successful flow + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + restMock.onGet(contractResultEndpoint).reply(200, JSON.stringify({ hash: ethereumHash })); + + lockServiceStub.acquireLock.resolves('test-session-key-success'); + lockServiceStub.releaseLock.resolves(); // Won't be called in sendRawTransaction + + sdkClientStub.submitEthereumTransaction.resolves({ + txResponse: { + transactionId: TransactionId.fromString(transactionIdServicesFormat), + } as unknown as TransactionResponse, + fileId: null, + }); + + const result = await ethImpl.sendRawTransaction(signed, requestDetails); + + expect(result).to.equal(ethereumHash); + + // Verify lock was acquired + sinon.assert.calledOnce(lockServiceStub.acquireLock); + sinon.assert.calledWith(lockServiceStub.acquireLock, accountAddress); + + // Verify lock was NOT released in sendRawTransaction + // (it should be released later in the chain, in sdkClient.executeTransaction) + sinon.assert.notCalled(lockServiceStub.releaseLock); + + // Verify no error logs + sinon.assert.notCalled(loggerErrorStub); + }); + + withOverriddenEnvsInMochaTest({ ENABLE_NONCE_ORDERING: false }, () => { + it('should not get session key when ENABLE_NONCE_ORDERING is disabled', async function () { + const signed = await signTransaction(transaction); + + // Mock successful flow + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + restMock.onGet(contractResultEndpoint).reply(200, JSON.stringify({ hash: ethereumHash })); + + sdkClientStub.submitEthereumTransaction.resolves({ + txResponse: { + transactionId: TransactionId.fromString(transactionIdServicesFormat), + } as unknown as TransactionResponse, + fileId: null, + }); + + const result = await ethImpl.sendRawTransaction(signed, requestDetails); + + expect(result).to.equal(ethereumHash); + + // Verify lock was NOT acquired when feature is disabled + sinon.assert.calledOnce(lockServiceStub.acquireLock); + const returnValue = await lockServiceStub.acquireLock.getCall(0).returnValue; + expect(returnValue).to.equal(undefined); + sinon.assert.notCalled(lockServiceStub.releaseLock); + }); + }); + }); + }); + + describe('Consensus Submission Lock Release', () => { + overrideEnvsInMochaDescribe({ ENABLE_NONCE_ORDERING: true }); + + let lockServiceStub: sinon.SinonStubbedInstance; + let sendRawTransactionProcessorSpy: sinon.SinonSpy; + + beforeEach(() => { + lockServiceStub = sinon.createStubInstance(LockService); + ethImpl['transactionService']['lockService'] = lockServiceStub; + sendRawTransactionProcessorSpy = sinon.spy(ethImpl['transactionService'], 'sendRawTransactionProcessor'); + }); + + afterEach(() => { + sendRawTransactionProcessorSpy.restore(); + }); + + it('should release lock immediately after consensus submission succeeds', async function () { + const signed = await signTransaction(transaction); + const computeHashSpy = sinon.spy(Utils, 'computeTransactionHash'); + + try { + // Mock successful flow + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + restMock.onGet(contractResultEndpoint).reply(200, JSON.stringify({ hash: ethereumHash })); + + lockServiceStub.acquireLock.resolves('session-after-consensus-1'); + lockServiceStub.releaseLock.resolves(); + + sdkClientStub.submitEthereumTransaction.resolves({ + txResponse: { + transactionId: TransactionId.fromString(transactionIdServicesFormat), + } as unknown as TransactionResponse, + fileId: null, + }); + + const result = await ethImpl.sendRawTransaction(signed, requestDetails); + + // In async mode, wait for background processing to complete + if (useAsyncTxProcessing) { + await clock.tickAsync(1); + } + + expect(result).to.equal(ethereumHash); + + // Verify lock was released after submitEthereumTransaction + sinon.assert.calledOnce(lockServiceStub.releaseLock); + sinon.assert.calledWith(lockServiceStub.releaseLock, accountAddress, 'session-after-consensus-1'); + + expect(sdkClientStub.submitEthereumTransaction.calledBefore(lockServiceStub.releaseLock)).to.be.true; + + // In async mode, verify computeHash was called before lock release + if (useAsyncTxProcessing) { + sinon.assert.calledOnce(computeHashSpy); + expect(sendRawTransactionProcessorSpy.calledBefore(computeHashSpy)).to.be.true; + expect(computeHashSpy.calledBefore(lockServiceStub.releaseLock)).to.be.true; + } + } finally { + computeHashSpy.restore(); + } + }); + + it('should release lock even when mirror node polling fails after consensus', async function () { + const signed = await signTransaction(transaction); + + // Mock successful consensus but failed mirror node polling + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + restMock.onGet(contractResultEndpoint).reply(404, JSON.stringify(mockData.notFound)); + + lockServiceStub.acquireLock.resolves('session-mn-fail'); + lockServiceStub.releaseLock.resolves(); + + sdkClientStub.submitEthereumTransaction.resolves({ + txResponse: { + transactionId: TransactionId.fromString(transactionIdServicesFormat), + } as unknown as TransactionResponse, + fileId: null, + }); + + const result = await ethImpl.sendRawTransaction(signed, requestDetails); + if (useAsyncTxProcessing) await clock.tickAsync(1); + // Should return txHash because of async processing + expect(result).to.equal(ethereumHash); + + // Verify lock was released despite MN polling failure + sinon.assert.calledOnce(lockServiceStub.releaseLock); + sinon.assert.calledWith(lockServiceStub.releaseLock, accountAddress, 'session-mn-fail'); + }); + + it('should not release lock when lockSessionKey is undefined', async function () { + const signed = await signTransaction(transaction); + + // Mock successful flow + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + restMock.onGet(contractResultEndpoint).reply(200, JSON.stringify({ hash: ethereumHash })); + + // Lock acquisition returns undefined (lock not acquired) + lockServiceStub.acquireLock.resolves(undefined as any); + lockServiceStub.releaseLock.resolves(); + + sdkClientStub.submitEthereumTransaction.resolves({ + txResponse: { + transactionId: TransactionId.fromString(transactionIdServicesFormat), + } as unknown as TransactionResponse, + fileId: null, + }); + + const result = await ethImpl.sendRawTransaction(signed, requestDetails); + + expect(result).to.equal(ethereumHash); + + // Verify lock release was NOT attempted + sinon.assert.notCalled(lockServiceStub.releaseLock); + }); + + withOverriddenEnvsInMochaTest({ USE_ASYNC_TX_PROCESSING: false }, () => { + it('should release lock during synchronous processing when async mode is disabled', async function () { + const signed = await signTransaction(transaction); + const computeHashSpy = sinon.spy(Utils, 'computeTransactionHash'); + + try { + // Mock successful flow + restMock.onGet(accountEndpoint).reply(200, JSON.stringify(ACCOUNT_RES)); + restMock.onGet(receiverAccountEndpoint).reply(200, JSON.stringify(RECEIVER_ACCOUNT_RES)); + restMock.onGet(networkExchangeRateEndpoint).reply(200, JSON.stringify(mockedExchangeRate)); + restMock.onGet(contractResultEndpoint).reply(200, JSON.stringify({ hash: ethereumHash })); + + lockServiceStub.acquireLock.resolves('session-sync'); + lockServiceStub.releaseLock.resolves(); + + sdkClientStub.submitEthereumTransaction.resolves({ + txResponse: { + transactionId: TransactionId.fromString(transactionIdServicesFormat), + } as unknown as TransactionResponse, + fileId: null, + }); + + const result = await ethImpl.sendRawTransaction(signed, requestDetails); + + // Should return hash from mirror node (not computed) + expect(result).to.equal(ethereumHash); + sinon.assert.notCalled(computeHashSpy); + // Verify lock was released during synchronous execution (no need to tick clock) + sinon.assert.calledOnce(lockServiceStub.releaseLock); + sinon.assert.calledWith(lockServiceStub.releaseLock, accountAddress, 'session-sync'); + + expect(sdkClientStub.submitEthereumTransaction.calledBefore(lockServiceStub.releaseLock)).to.be.true; + } finally { + computeHashSpy.restore(); + } + }); + }); + }); }); }); diff --git a/packages/relay/tests/lib/openrpc.spec.ts b/packages/relay/tests/lib/openrpc.spec.ts index 0ce03609b2..d38d0b1241 100644 --- a/packages/relay/tests/lib/openrpc.spec.ts +++ b/packages/relay/tests/lib/openrpc.spec.ts @@ -28,6 +28,7 @@ import { NetImpl } from '../../src/lib/net'; import { CacheService } from '../../src/lib/services/cacheService/cacheService'; import ClientService from '../../src/lib/services/hapiService/hapiService'; import { HbarLimitService } from '../../src/lib/services/hbarLimitService'; +import { LockService } from '../../src/lib/services/lockService/LockService'; import { TxPoolImpl } from '../../src/lib/txpool'; import { RequestDetails } from '../../src/lib/types'; import { Web3Impl } from '../../src/lib/web3'; @@ -131,14 +132,23 @@ describe('Open RPC Specification', function () { clientServiceInstance = new ClientService(logger, registry, hbarLimitService); sdkClientStub = sinon.createStubInstance(SDKClient); sinon.stub(clientServiceInstance, 'getSDKClient').returns(sdkClientStub); - ethImpl = new EthImpl(clientServiceInstance, mirrorNodeInstance, logger, '0x12a', cacheService); + const lockServiceStub = sinon.createStubInstance(LockService); + lockServiceStub.acquireLock.resolves(undefined); ns = { eth: ethImpl, net: new NetImpl(), web3: new Web3Impl() }; const storageStub = sinon.createStubInstance(LocalPendingTransactionStorage); const rlpTx = '0x01f871808209b085a54f4c3c00830186a0949b6feaea745fe564158da9a5313eb4dd4dc3a940880de0b6b3a764000080c080a05e2d00db2121fdd3c761388c64fc72d123f17e67fddd85a41c819694196569b5a03dc6b2429ed7694f42cdc46309e08cc78eb96864a0da58537fe938d4d9f334f2'; storageStub.getTransactionPayloads.resolves(new Set([rlpTx])); storageStub.getAllTransactionPayloads.resolves(new Set([rlpTx])); - ethImpl = new EthImpl(clientServiceInstance, mirrorNodeInstance, logger, '0x12a', cacheService, storageStub); + ethImpl = new EthImpl( + clientServiceInstance, + mirrorNodeInstance, + logger, + '0x12a', + cacheService, + storageStub, + lockServiceStub, + ); txpoolImpl = new TxPoolImpl(storageStub, logger); ns = { eth: ethImpl, net: new NetImpl(), web3: new Web3Impl(), txpool: txpoolImpl }; diff --git a/packages/relay/tests/lib/services/lockService/LocalLockStrategy.spec.ts b/packages/relay/tests/lib/services/lockService/LocalLockStrategy.spec.ts new file mode 100644 index 0000000000..9583a49502 --- /dev/null +++ b/packages/relay/tests/lib/services/lockService/LocalLockStrategy.spec.ts @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { expect } from 'chai'; +import { pino } from 'pino'; +import sinon from 'sinon'; + +import { LocalLockStrategy, LockState } from '../../../../src/lib/services/lockService/LocalLockStrategy'; +import { withOverriddenEnvsInMochaTest } from '../../../helpers'; + +describe('LocalLockStrategy', function () { + this.timeout(10000); + + let lockStrategy: LocalLockStrategy; + + beforeEach(() => { + lockStrategy = new LocalLockStrategy(pino({ level: 'silent' })); + }); + + afterEach(() => { + sinon.restore(); + }); + + function getStateEntry(address: string): LockState | null { + return lockStrategy['localLockStates'].get(address); + } + + it('should acquire and release a lock successfully', async () => { + const address = 'test-address'; + + const sessionKey = await lockStrategy.acquireLock(address); + expect(sessionKey).to.be.a('string'); + + const lockEntryAfterAcquisition = getStateEntry(address); + expect(lockEntryAfterAcquisition.sessionKey).to.not.be.null; + + await lockStrategy.releaseLock(address, sessionKey); + const lockEntryAfterRelease = getStateEntry(address); + expect(lockEntryAfterRelease.sessionKey).to.be.null; + }); + + it('should not allow a non-owner to release a lock', async () => { + const address = 'test-non-owner'; + const sessionKey = await lockStrategy.acquireLock(address); + + const lockEntryAfterAcquisition = getStateEntry(address); + expect(lockEntryAfterAcquisition.sessionKey).to.equal(sessionKey); + + const wrongKey = 'fake-session'; + const doReleaseSpy = sinon.spy(lockStrategy as any, 'doRelease'); + await lockStrategy.releaseLock(address, wrongKey); + + const lockEntryAfterFakeRelease = getStateEntry(address); + expect(lockEntryAfterFakeRelease.sessionKey).to.equal(sessionKey); + expect(doReleaseSpy.called).to.be.false; + + await lockStrategy.releaseLock(address, sessionKey); + + const lockEntryAfterRelease = getStateEntry(address); + expect(lockEntryAfterRelease.sessionKey).to.be.null; + }); + + it('should block a second acquire until the first is released', async () => { + const address = 'test-sequential'; + + const sessionKey1 = await lockStrategy.acquireLock(address); + let secondAcquired = false; + + const acquire2 = (async () => { + const key2 = await lockStrategy.acquireLock(address); + secondAcquired = true; + await lockStrategy.releaseLock(address, key2); + })(); + + // Wait 100ms to ensure second acquire is blocked + await new Promise((res) => setTimeout(res, 100)); + expect(secondAcquired).to.be.false; + + // Now release first + await lockStrategy.releaseLock(address, sessionKey1); + + // Wait for second acquire to complete + await acquire2; + expect(secondAcquired).to.be.true; + }); + + withOverriddenEnvsInMochaTest({ LOCK_MAX_HOLD_MS: 200 }, () => { + it('should auto-release after max lock time', async () => { + const address = 'test-auto-release'; + + const releaseSpy = sinon.spy(lockStrategy as any, 'doRelease'); + await lockStrategy.acquireLock(address); + + // Wait beyond auto-release timeout + await new Promise((res) => setTimeout(res, 300)); + + expect(releaseSpy.called).to.be.true; + const args = releaseSpy.getCall(0).args[0]; + expect(args.sessionKey).to.be.null; + }); + }); + + it('should reuse existing lock state for same address', async () => { + const address = 'test-reuse'; + + const state1 = lockStrategy['getOrCreateState'](address); + const state2 = lockStrategy['getOrCreateState'](address); + + expect(state1).to.equal(state2); + }); + + it('should create a new lock state for new addresses', async () => { + const stateA = lockStrategy['getOrCreateState']('a'); + const stateB = lockStrategy['getOrCreateState']('b'); + + expect(stateA).to.not.equal(stateB); + }); + + it('should clear timeout and reset state on release', async () => { + const address = 'test-reset'; + const sessionKey = await lockStrategy.acquireLock(address); + const state = lockStrategy['localLockStates'].get(address); + + expect(state.sessionKey).to.equal(sessionKey); + expect(state.lockTimeoutId).to.not.be.null; + + await lockStrategy.releaseLock(address, sessionKey); + + expect(state.sessionKey).to.be.null; + expect(state.lockTimeoutId).to.be.null; + expect(state.acquiredAt).to.be.null; + }); + + it('should ignore forceReleaseExpiredLock if session key does not match', async () => { + const address = 'test-force-mismatch'; + const sessionKey = await lockStrategy.acquireLock(address); + + const state = lockStrategy['localLockStates'].get(address); + expect(state.sessionKey).to.equal(sessionKey); + + // Modify session key to simulate ownership change + state.sessionKey = 'different-key'; + + const doReleaseSpy = sinon.spy(lockStrategy as any, 'doRelease'); + await lockStrategy['forceReleaseExpiredLock'](address, sessionKey); + + expect(doReleaseSpy.called).to.be.false; + + await lockStrategy.releaseLock(address, 'different-key'); + }); +}); diff --git a/packages/relay/tests/lib/services/lockService/RedisLockStrategy.spec.ts b/packages/relay/tests/lib/services/lockService/RedisLockStrategy.spec.ts new file mode 100644 index 0000000000..290c5db68c --- /dev/null +++ b/packages/relay/tests/lib/services/lockService/RedisLockStrategy.spec.ts @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: Apache-2.0 + +import { expect, use } from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import { Logger, pino } from 'pino'; +import { RedisClientType } from 'redis'; +import * as sinon from 'sinon'; + +import { RedisLockStrategy } from '../../../../src/lib/services/lockService/RedisLockStrategy'; + +use(chaiAsPromised); + +describe('RedisLockStrategy Test Suite', function () { + this.timeout(10000); + + let logger: Logger; + let mockRedisClient: sinon.SinonStubbedInstance; + let redisLockStrategy: RedisLockStrategy; + + const testAddress = '0x1234567890abcdef1234567890abcdef12345678'; + const normalizedAddress = testAddress.toLowerCase(); + + beforeEach(() => { + logger = pino({ level: 'silent' }); + + // Create a mock Redis client + mockRedisClient = { + lPush: sinon.stub(), + lIndex: sinon.stub(), + set: sinon.stub(), + lRem: sinon.stub(), + lLen: sinon.stub(), + eval: sinon.stub(), + } as any; + + redisLockStrategy = new RedisLockStrategy(mockRedisClient as any, logger); + }); + + afterEach(() => { + sinon.restore(); + }); + + describe('acquireLock', () => { + it('should successfully acquire lock when first in queue', async () => { + const sessionKey = 'test-session-key'; + + // Mock queue operations + mockRedisClient.lPush.resolves(1); + mockRedisClient.lIndex.resolves(sessionKey); + mockRedisClient.set.resolves('OK'); + mockRedisClient.lRem.resolves(1); + mockRedisClient.lLen.resolves(0); + + // Stub generateSessionKey to return predictable value + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(sessionKey); + + const result = await redisLockStrategy.acquireLock(testAddress); + + expect(result).to.equal(sessionKey); + expect(mockRedisClient.lPush.calledOnce).to.be.true; + expect(mockRedisClient.lPush.calledWith(`lock:queue:${normalizedAddress}`, sessionKey)).to.be.true; + expect(mockRedisClient.set.calledOnce).to.be.true; + expect(mockRedisClient.lRem.calledOnce).to.be.true; + expect(mockRedisClient.lRem.calledWith(`lock:queue:${normalizedAddress}`, 1, sessionKey)).to.be.true; + }); + + it('should wait in queue until first position', async () => { + const sessionKey = 'test-session-key'; + const otherSessionKey = 'other-session-key'; + + // Mock queue operations - first call returns other session, second returns our session + mockRedisClient.lPush.resolves(2); + mockRedisClient.lIndex.onFirstCall().resolves(otherSessionKey).onSecondCall().resolves(sessionKey); + mockRedisClient.set.resolves('OK'); + mockRedisClient.lRem.resolves(1); + mockRedisClient.lLen.resolves(1); + + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(sessionKey); + + const result = await redisLockStrategy.acquireLock(testAddress); + + expect(result).to.equal(sessionKey); + expect(mockRedisClient.lIndex.callCount).to.equal(2); + expect(mockRedisClient.lRem.calledOnce).to.be.true; + }); + + it('should normalize address to lowercase', async () => { + const sessionKey = 'test-session-key'; + const upperCaseAddress = '0xABCDEF1234567890ABCDEF1234567890ABCDEF12'; + + mockRedisClient.lPush.resolves(1); + mockRedisClient.lIndex.resolves(sessionKey); + mockRedisClient.set.resolves('OK'); + mockRedisClient.lRem.resolves(1); + mockRedisClient.lLen.resolves(0); + + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(sessionKey); + + await redisLockStrategy.acquireLock(upperCaseAddress); + + expect(mockRedisClient.lPush.calledWith(`lock:queue:${upperCaseAddress.toLowerCase()}`, sessionKey)).to.be.true; + expect(mockRedisClient.lRem.calledWith(`lock:queue:${upperCaseAddress.toLowerCase()}`, 1, sessionKey)).to.be.true; + }); + + it('should handle Redis errors during acquisition and cleanup queue (fail open)', async () => { + const sessionKey = 'test-session-key'; + const redisError = new Error('Redis connection failed'); + + // lPush succeeds, but lIndex fails + mockRedisClient.lPush.resolves(1); + mockRedisClient.lIndex.rejects(redisError); + mockRedisClient.lRem.resolves(1); + + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(sessionKey); + + const result = await redisLockStrategy.acquireLock(testAddress); + + // Should return null (fail open) instead of throwing + expect(result).to.be.undefined; + + // Should have attempted cleanup + expect(mockRedisClient.lRem.calledOnce).to.be.true; + expect(mockRedisClient.lRem.calledWith(`lock:queue:${normalizedAddress}`, 1, sessionKey)).to.be.true; + }); + + it('should handle Redis errors before joining queue without cleanup (fail open)', async () => { + const sessionKey = 'test-session-key'; + const redisError = new Error('Redis connection failed'); + + // lPush fails immediately + mockRedisClient.lPush.rejects(redisError); + + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(sessionKey); + + const result = await redisLockStrategy.acquireLock(testAddress); + + // Should return null (fail open) instead of throwing + expect(result).to.be.undefined; + + // Should NOT have attempted cleanup (never joined queue) + expect(mockRedisClient.lRem.called).to.be.false; + }); + }); + + describe('releaseLock', () => { + it('should successfully release lock with valid session key', async () => { + const sessionKey = 'test-session-key'; + + // Mock Lua script execution - return 1 for successful deletion + mockRedisClient.eval.resolves(1); + + await redisLockStrategy.releaseLock(testAddress, sessionKey); + + expect(mockRedisClient.eval.calledOnce).to.be.true; + const evalCall = mockRedisClient.eval.getCall(0); + expect(evalCall.args[0]).to.be.a('string'); // Lua script + expect(evalCall.args[1]).to.deep.equal({ + keys: [`lock:${normalizedAddress}`], + arguments: [sessionKey], + }); + }); + + it('should ignore release with invalid session key', async () => { + const sessionKey = 'test-session-key'; + + // Mock Lua script execution - return 0 for no deletion (not owner) + mockRedisClient.eval.resolves(0); + + // Should not throw + await redisLockStrategy.releaseLock(testAddress, sessionKey); + + expect(mockRedisClient.eval.calledOnce).to.be.true; + }); + + it('should handle Redis errors during release gracefully', async () => { + const sessionKey = 'test-session-key'; + const redisError = new Error('Redis connection failed'); + + mockRedisClient.eval.rejects(redisError); + + // Should not throw - release failures should not block caller + await redisLockStrategy.releaseLock(testAddress, sessionKey); + + expect(mockRedisClient.eval.calledOnce).to.be.true; + }); + + it('should normalize address during release', async () => { + const sessionKey = 'test-session-key'; + const upperCaseAddress = '0xABCDEF1234567890ABCDEF1234567890ABCDEF12'; + + mockRedisClient.eval.resolves(1); + + await redisLockStrategy.releaseLock(upperCaseAddress, sessionKey); + + const evalCall = mockRedisClient.eval.getCall(0); + expect(evalCall).to.not.be.null; + expect((evalCall as any).args[1].keys[0]).to.equal(`lock:${upperCaseAddress.toLowerCase()}`); + }); + }); + + describe('FIFO ordering', () => { + it('should maintain FIFO order for multiple waiters', async () => { + const session1 = 'session-1'; + + // Simulate session joining queue + mockRedisClient.lPush.resolves(1); + + // First session acquires immediately + mockRedisClient.lIndex.onCall(0).resolves(session1); + mockRedisClient.set.onCall(0).resolves('OK'); + mockRedisClient.lRem.onCall(0).resolves(1); + mockRedisClient.lLen.resolves(2); + + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(session1); + + const result1 = await redisLockStrategy.acquireLock(testAddress); + expect(result1).to.equal(session1); + + // Verify LPUSH was called (adding to queue) + expect(mockRedisClient.lPush.calledWith(`lock:queue:${normalizedAddress}`, session1)).to.be.true; + // Verify LREM was called (removing from queue) + expect(mockRedisClient.lRem.calledWith(`lock:queue:${normalizedAddress}`, 1, session1)).to.be.true; + }); + }); + + describe('TTL-based expiration', () => { + it('should set TTL when acquiring lock', async () => { + const sessionKey = 'test-session-key'; + + mockRedisClient.lPush.resolves(1); + mockRedisClient.lIndex.resolves(sessionKey); + mockRedisClient.set.resolves('OK'); + mockRedisClient.lRem.resolves(1); + mockRedisClient.lLen.resolves(0); + + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(sessionKey); + + await redisLockStrategy.acquireLock(testAddress); + + // Verify SET was called with NX and PX options + const setCall = mockRedisClient.set.getCall(0); + expect(setCall.args[0]).to.equal(`lock:${normalizedAddress}`); + expect(setCall.args[1]).to.equal(sessionKey); + expect(setCall.args[2]).to.deep.include({ NX: true }); + expect(setCall.args[2]).to.have.property('PX'); + }); + }); + + describe('Error handling and resilience', () => { + it('should handle cleanup failures gracefully', async () => { + const sessionKey = 'test-session-key'; + const redisError = new Error('Redis connection failed'); + + // lPush succeeds, lIndex fails, lRem also fails + mockRedisClient.lPush.resolves(1); + mockRedisClient.lIndex.rejects(redisError); + mockRedisClient.lRem.rejects(new Error('Cleanup failed')); + + sinon.stub(redisLockStrategy as any, 'generateSessionKey').returns(sessionKey); + + const result = await redisLockStrategy.acquireLock(testAddress); + + // Should return null (fail open) instead of throwing + expect(result).to.be.undefined; + + // Cleanup was attempted + expect(mockRedisClient.lRem.calledOnce).to.be.true; + }); + }); +}); diff --git a/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts b/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts index bca01434c0..508d5dbd24 100644 --- a/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts +++ b/packages/server/tests/acceptance/sendRawTransactionExtension.spec.ts @@ -9,6 +9,7 @@ import Constants from '@hashgraph/json-rpc-relay/dist/lib/constants'; // Errors and constants from local resources import { predefined } from '@hashgraph/json-rpc-relay/dist/lib/errors/JsonRpcError'; import { RequestDetails } from '@hashgraph/json-rpc-relay/dist/lib/types'; +import { overrideEnvsInMochaDescribe, withOverriddenEnvsInMochaTest } from '@hashgraph/json-rpc-relay/tests/helpers'; import { expect } from 'chai'; import MirrorClient from '../clients/mirrorClient'; @@ -32,6 +33,15 @@ describe('@sendRawTransactionExtension Acceptance Tests', function () { }: { servicesNode: ServicesClient; mirrorNode: MirrorClient; relay: RelayClient; initialBalance: string } = global; const CHAIN_ID = ConfigService.get('CHAIN_ID'); + const ONE_TINYBAR = Utils.add0xPrefix(Utils.toHex(Constants.TINYBAR_TO_WEIBAR_COEF)); + const defaultLondonTransactionData = { + value: ONE_TINYBAR, + chainId: Number(CHAIN_ID), + maxPriorityFeePerGas: Assertions.defaultGasPrice, + maxFeePerGas: Assertions.defaultGasPrice, + gasLimit: numberTo0x(3_000_000), + type: 2, + }; const requestDetails = new RequestDetails({ requestId: 'sendRawTransactionPrecheck', ipAddress: '0.0.0.0' }); const sendRawTransaction = relay.sendRawTransaction; @@ -41,7 +51,7 @@ describe('@sendRawTransactionExtension Acceptance Tests', function () { this.beforeAll(async () => { const initialAccount: AliasAccount = global.accounts[0]; - const neededAccounts: number = 3; + const neededAccounts: number = 5; accounts.push( ...(await Utils.createMultipleAliasAccounts(mirrorNode, initialAccount, neededAccounts, initialBalance)), ); @@ -202,6 +212,19 @@ describe('@sendRawTransactionExtension Acceptance Tests', function () { const GAS_PRICE_REF = '0x123456'; const MAX_ALLOWANCE = 100; + let paymasterEnabledBefore, paymasterWhitelistBefore, maxGasAllowanceHbarBefore; + before(() => { + paymasterEnabledBefore = ConfigService.get('PAYMASTER_ENABLED'); + paymasterWhitelistBefore = ConfigService.get('PAYMASTER_WHITELIST'); + maxGasAllowanceHbarBefore = ConfigService.get('MAX_GAS_ALLOWANCE_HBAR'); + }); + + after(() => { + ConfigServiceTestHelper.dynamicOverride('PAYMASTER_ENABLED', paymasterEnabledBefore); + ConfigServiceTestHelper.dynamicOverride('PAYMASTER_WHITELIST', paymasterWhitelistBefore); + ConfigServiceTestHelper.dynamicOverride('MAX_GAS_ALLOWANCE_HBAR', maxGasAllowanceHbarBefore); + }); + const configurePaymaster = (enabled: boolean, whitelist: string[], allowance: number) => { ConfigServiceTestHelper.dynamicOverride('PAYMASTER_ENABLED', enabled); ConfigServiceTestHelper.dynamicOverride('PAYMASTER_WHITELIST', whitelist); @@ -297,4 +320,207 @@ describe('@sendRawTransactionExtension Acceptance Tests', function () { expect(info.result).to.equal('INSUFFICIENT_TX_FEE'); }); }); + + describe('@nonce-ordering Lock Service Tests', function () { + this.timeout(240 * 1000); // 240 seconds + overrideEnvsInMochaDescribe({ ENABLE_NONCE_ORDERING: true, USE_ASYNC_TX_PROCESSING: true }); + const sendTransactionWithoutWaiting = (signer: any, nonce: number, numOfTxs: number, gasPrice: number) => { + const txPromises = Array.from({ length: numOfTxs }, async (_, i) => { + const tx = { + ...defaultLondonTransactionData, + to: accounts[2].address, + value: ONE_TINYBAR, + nonce: nonce + i, + maxPriorityFeePerGas: gasPrice, + maxFeePerGas: gasPrice, + }; + const signedTx = await signer.wallet.signTransaction(tx); + return relay.sendRawTransaction(signedTx); + }); + + return txPromises; + }; + + it('should handle rapid burst of 10 transactions from same sender', async function () { + const sender = accounts[1]; + const startNonce = await relay.getAccountNonce(sender.address); + const gasPrice = await relay.gasPrice(); + + const txPromises = sendTransactionWithoutWaiting(sender, startNonce, 10, gasPrice); + const txHashes = await Promise.all(txPromises); + const receipts = await Promise.all(txHashes.map((txHash) => relay.pollForValidTransactionReceipt(txHash))); + + receipts.forEach((receipt, i) => { + expect(receipt.status).to.equal('0x1', `Transaction ${i} failed`); + }); + + const finalNonce = await relay.getAccountNonce(sender.address); + expect(finalNonce).to.equal(startNonce + 10); + }); + + it('should process three transactions from different senders concurrently', async function () { + const senders = [accounts[0], accounts[1], accounts[3]]; + const startNonces = await Promise.all(senders.map((sender) => relay.getAccountNonce(sender.address))); + const gasPrice = await relay.gasPrice(); + + const startTime = Date.now(); + + // Send transactions from different senders simultaneously + const txPromises = senders.flatMap((sender, i) => + sendTransactionWithoutWaiting(sender, startNonces[i], 1, gasPrice), + ); + + const txHashes = await Promise.all(txPromises); + const submitTime = Date.now() - startTime; + + // All should succeed + const receipts = await Promise.all(txHashes.map((hash) => relay.pollForValidTransactionReceipt(hash))); + + receipts.forEach((receipt) => { + expect(receipt.status).to.equal('0x1'); + }); + + // Verify nonces incremented for each sender independently + const finalNonces = await Promise.all(senders.map((sender) => relay.getAccountNonce(sender.address))); + + finalNonces.forEach((nonce, i) => { + expect(nonce).to.equal(startNonces[i] + 1); + }); + + // Submission should be fast (not blocking each other) + // Even with network latency, parallel submission should be < 5 seconds + expect(submitTime).to.be.lessThan(5000); + }); + + it('should handle mixed load: 5 txs each from 3 different senders', async function () { + const senders = [accounts[0], accounts[1], accounts[3]]; + const startNonces = await Promise.all(senders.map((sender) => relay.getAccountNonce(sender.address))); + const gasPrice = await relay.gasPrice(); + + // Each sender sends 5 transactions + const allTxPromises = senders.flatMap((sender, senderIdx) => + sendTransactionWithoutWaiting(sender, startNonces[senderIdx], 5, gasPrice), + ); + + const txHashes = await Promise.all(allTxPromises); + + const receipts = await Promise.all(txHashes.map((txHash) => relay.pollForValidTransactionReceipt(txHash))); + receipts.forEach((receipt, i) => { + expect(receipt.status).to.equal('0x1', `Transaction ${i} failed`); + }); + + const finalNonces = await Promise.all(senders.map((sender) => relay.getAccountNonce(sender.address))); + + finalNonces.forEach((nonce, i) => { + expect(nonce).to.equal(startNonces[i] + 5); + }); + }); + + it('should release lock after consensus submission in async mode', async function () { + const sender = accounts[0]; + const startNonce = await relay.getAccountNonce(sender.address); + const gasPrice = await relay.gasPrice(); + + // Send first transaction + const tx1Hash = await (await sendTransactionWithoutWaiting(sender, startNonce, 1, gasPrice))[0]; + + // Immediately send second transaction (should queue behind first) + const tx2Hash = await (await sendTransactionWithoutWaiting(sender, startNonce + 1, 1, gasPrice))[0]; + + // In async mode, both should return immediately with tx hashes + expect(tx1Hash).to.exist; + expect(tx2Hash).to.exist; + + // Both should eventually succeed + const receipt1 = await relay.pollForValidTransactionReceipt(tx1Hash); + const receipt2 = await relay.pollForValidTransactionReceipt(tx2Hash); + + expect(receipt1.status).to.equal('0x1'); + expect(receipt2.status).to.equal('0x1'); + + // Verify correct nonces + const result1 = await mirrorNode.get(`/contracts/results/${tx1Hash}`); + const result2 = await mirrorNode.get(`/contracts/results/${tx2Hash}`); + + expect(result1.nonce).to.equal(startNonce); + expect(result2.nonce).to.equal(startNonce + 1); + }); + + withOverriddenEnvsInMochaTest({ USE_ASYNC_TX_PROCESSING: false }, () => { + it('should release lock after full processing in sync mode', async function () { + const sender = accounts[0]; + const startNonce = await relay.getAccountNonce(sender.address); + const gasPrice = await relay.gasPrice(); + + // Submit both transactions concurrently (no await until Promise.all) + const tx1Promise = sendTransactionWithoutWaiting(sender, startNonce, 1, gasPrice); + const tx2Promise = sendTransactionWithoutWaiting(sender, startNonce + 1, 1, gasPrice); + + // Wait for both to complete (lock service ensures they process sequentially internally) + const [tx1Hashes, tx2Hashes] = await Promise.all([tx1Promise[0], tx2Promise[0]]); + const tx1Hash = tx1Hashes; + const tx2Hash = tx2Hashes; + + // Both should succeed - no WRONG_NONCE errors + expect(tx1Hash).to.exist; + expect(tx2Hash).to.exist; + + const receipts = await Promise.all([ + relay.pollForValidTransactionReceipt(tx1Hash), + relay.pollForValidTransactionReceipt(tx2Hash), + ]); + + expect(receipts[0].status).to.equal('0x1'); + expect(receipts[0].status).to.equal('0x1'); + }); + + it('should release lock and allow next transaction after gas price validation error', async function () { + const sender = accounts[0]; + const startNonce = await relay.getAccountNonce(sender.address); + const tooLowGasPrice = '0x0'; // Intentionally too low + + // First tx with invalid gas price (will fail validation and not reach consensus) + const invalidTx = { + value: ONE_TINYBAR, + chainId: Number(CHAIN_ID), + maxPriorityFeePerGas: tooLowGasPrice, + maxFeePerGas: tooLowGasPrice, + gasLimit: numberTo0x(3_000_000), + type: 2, + to: accounts[2].address, + nonce: startNonce, + }; + const signedInvalidTx = await sender.wallet.signTransaction(invalidTx); + + // Second tx with correct nonce (startNonce + 1), but will fail with WRONG_NONCE + // because first tx never executed (account's actual nonce is still startNonce) + const secondTx = { + ...defaultLondonTransactionData, + to: accounts[2].address, + value: ONE_TINYBAR, + nonce: startNonce + 1, // This nonce is ahead of the account's actual nonce + }; + const signedSecondTx = await sender.wallet.signTransaction(secondTx); + + // Submit both transactions immediately to test lock release + const invalidTxPromise = relay.call('eth_sendRawTransaction', [signedInvalidTx]).catch((error: any) => error); + const secondTxPromise = relay.sendRawTransaction(signedSecondTx).catch((error: any) => error); + + // Wait for both to complete + const [invalidResult, wrongNonceError] = await Promise.all([invalidTxPromise, secondTxPromise]); + // Verify first tx failed with validation error + expect(invalidResult).to.be.instanceOf(Error); + expect(invalidResult.message).to.include('gas price'); + // Verify lock was released (second tx was allowed to proceed) + expect(wrongNonceError).to.be.instanceOf(Error); + expect(wrongNonceError.message).to.include('nonce'); + // Wait for second tx to be processed + await new Promise((r) => setTimeout(r, 2100)); + + // Verify account nonce hasn't changed (neither tx succeeded) + const finalNonce = await relay.getAccountNonce(sender.address); + expect(finalNonce).to.equal(startNonce); + }); + }); + }); });