From c93b58ed8c8d727c93f4958c182fed8b679ba560 Mon Sep 17 00:00:00 2001 From: Sasha Date: Sat, 19 Oct 2024 17:02:38 +0200 Subject: [PATCH 01/12] up lock --- package-lock.json | 66 +++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index afea4d840b..b819d96306 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40247,14 +40247,14 @@ }, "packages/core": { "name": "@waku/core", - "version": "0.0.32", + "version": "0.0.33", "license": "MIT OR Apache-2.0", "dependencies": { "@libp2p/ping": "^1.1.2", - "@waku/enr": "^0.0.26", - "@waku/interfaces": "0.0.27", + "@waku/enr": "^0.0.27", + "@waku/interfaces": "0.0.28", "@waku/proto": "0.0.8", - "@waku/utils": "0.0.20", + "@waku/utils": "0.0.21", "debug": "^4.3.4", "it-all": "^3.0.4", "it-length-prefixed": "^9.0.4", @@ -40312,14 +40312,14 @@ }, "packages/discovery": { "name": "@waku/discovery", - "version": "0.0.5", + "version": "0.0.6", "license": "MIT OR Apache-2.0", "dependencies": { - "@waku/core": "0.0.32", - "@waku/enr": "0.0.26", - "@waku/interfaces": "0.0.27", + "@waku/core": "0.0.33", + "@waku/enr": "0.0.27", + "@waku/interfaces": "0.0.28", "@waku/proto": "^0.0.8", - "@waku/utils": "0.0.20", + "@waku/utils": "0.0.21", "debug": "^4.3.4", "dns-query": "^0.11.2", "hi-base32": "^0.5.1", @@ -40358,7 +40358,7 @@ }, "packages/enr": { "name": "@waku/enr", - "version": "0.0.26", + "version": "0.0.27", "license": "MIT OR Apache-2.0", "dependencies": { "@ethersproject/rlp": "^5.7.0", @@ -40366,7 +40366,7 @@ "@libp2p/peer-id": "^4.2.1", "@multiformats/multiaddr": "^12.0.0", "@noble/secp256k1": "^1.7.1", - "@waku/utils": "0.0.20", + "@waku/utils": "0.0.21", "debug": "^4.3.4", "js-sha3": "^0.9.2" }, @@ -40378,7 +40378,7 @@ "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", "@waku/build-utils": "*", - "@waku/interfaces": "0.0.27", + "@waku/interfaces": "0.0.28", "chai": "^4.3.10", "cspell": "^8.6.1", "fast-check": "^3.19.0", @@ -40402,7 +40402,7 @@ }, "packages/interfaces": { "name": "@waku/interfaces", - "version": "0.0.27", + "version": "0.0.28", "license": "MIT OR Apache-2.0", "dependencies": { "@waku/proto": "^0.0.8" @@ -40420,14 +40420,14 @@ }, "packages/message-encryption": { "name": "@waku/message-encryption", - "version": "0.0.30", + "version": "0.0.31", "license": "MIT OR Apache-2.0", "dependencies": { "@noble/secp256k1": "^1.7.1", - "@waku/core": "0.0.32", - "@waku/interfaces": "0.0.27", + "@waku/core": "0.0.33", + "@waku/interfaces": "0.0.28", "@waku/proto": "0.0.8", - "@waku/utils": "0.0.20", + "@waku/utils": "0.0.21", "debug": "^4.3.4", "js-sha3": "^0.9.2", "uint8arrays": "^5.0.1" @@ -40453,11 +40453,11 @@ }, "packages/message-hash": { "name": "@waku/message-hash", - "version": "0.1.16", + "version": "0.1.17", "license": "MIT OR Apache-2.0", "dependencies": { "@noble/hashes": "^1.3.2", - "@waku/utils": "0.0.20" + "@waku/utils": "0.0.21" }, "devDependencies": { "@rollup/plugin-commonjs": "^25.0.7", @@ -40467,7 +40467,7 @@ "@types/debug": "^4.1.12", "@types/mocha": "^10.0.6", "@waku/build-utils": "*", - "@waku/interfaces": "0.0.27", + "@waku/interfaces": "0.0.28", "chai": "^4.3.10", "cspell": "^8.6.1", "fast-check": "^3.19.0", @@ -40526,16 +40526,16 @@ }, "packages/relay": { "name": "@waku/relay", - "version": "0.0.15", + "version": "0.0.16", "license": "MIT OR Apache-2.0", "dependencies": { "@chainsafe/libp2p-gossipsub": "^13.1.0", "@noble/hashes": "^1.3.2", - "@waku/core": "0.0.32", - "@waku/interfaces": "0.0.27", + "@waku/core": "0.0.33", + "@waku/interfaces": "0.0.28", "@waku/proto": "0.0.8", - "@waku/sdk": "0.0.28", - "@waku/utils": "0.0.20", + "@waku/sdk": "0.0.29", + "@waku/utils": "0.0.21", "chai": "^4.3.10", "debug": "^4.3.4", "fast-check": "^3.19.0", @@ -40562,7 +40562,7 @@ }, "packages/sdk": { "name": "@waku/sdk", - "version": "0.0.28", + "version": "0.0.29", "license": "MIT OR Apache-2.0", "dependencies": { "@chainsafe/libp2p-noise": "^15.1.0", @@ -40572,12 +40572,12 @@ "@libp2p/ping": "^1.1.2", "@libp2p/websockets": "^8.1.4", "@noble/hashes": "^1.3.3", - "@waku/core": "0.0.32", - "@waku/discovery": "0.0.5", - "@waku/interfaces": "0.0.27", - "@waku/message-hash": "0.1.16", + "@waku/core": "0.0.33", + "@waku/discovery": "0.0.6", + "@waku/interfaces": "0.0.28", + "@waku/message-hash": "0.1.17", "@waku/proto": "^0.0.8", - "@waku/utils": "0.0.20", + "@waku/utils": "0.0.21", "async-mutex": "^0.5.0", "libp2p": "^1.8.1" }, @@ -40745,11 +40745,11 @@ }, "packages/utils": { "name": "@waku/utils", - "version": "0.0.20", + "version": "0.0.21", "license": "MIT OR Apache-2.0", "dependencies": { "@noble/hashes": "^1.3.2", - "@waku/interfaces": "0.0.27", + "@waku/interfaces": "0.0.28", "chai": "^4.3.10", "debug": "^4.3.4", "uint8arrays": "^5.0.1" From 7efbd266094bc631fb55ddf38c7fc9e2f416586b Mon Sep 17 00:00:00 2001 From: Sasha Date: Sat, 19 Oct 2024 17:16:10 +0200 Subject: [PATCH 02/12] make ConnectionManager use ctor --- packages/core/src/lib/connection_manager.ts | 59 +++++++------------ packages/interfaces/src/connection_manager.ts | 2 +- packages/sdk/src/protocols/filter/index.ts | 2 +- .../src/protocols/light_push/light_push.ts | 5 +- packages/sdk/src/protocols/store/index.ts | 2 +- packages/sdk/src/waku/waku.ts | 11 ++-- 6 files changed, 29 insertions(+), 52 deletions(-) diff --git a/packages/core/src/lib/connection_manager.ts b/packages/core/src/lib/connection_manager.ts index 8fc61f4d54..fda6ff06bb 100644 --- a/packages/core/src/lib/connection_manager.ts +++ b/packages/core/src/lib/connection_manager.ts @@ -27,11 +27,21 @@ export const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1; export const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3; export const DEFAULT_MAX_PARALLEL_DIALS = 3; +type ConnectionManagerConstructorOptions = { + libp2p: Libp2p; + keepAliveOptions: KeepAliveOptions; + pubsubTopics: PubsubTopic[]; + relay?: IRelay; + config?: Partial; +}; + export class ConnectionManager extends TypedEventEmitter implements IConnectionManager { - private static instances = new Map(); + // TODO(weboko): make it private + public readonly pubsubTopics: PubsubTopic[]; + private keepAliveManager: KeepAliveManager; private options: ConnectionManagerOptions; private libp2p: Libp2p; @@ -51,29 +61,6 @@ export class ConnectionManager return this.isP2PNetworkConnected; } - public static create( - peerId: string, - libp2p: Libp2p, - keepAliveOptions: KeepAliveOptions, - pubsubTopics: PubsubTopic[], - relay?: IRelay, - options?: ConnectionManagerOptions - ): ConnectionManager { - let instance = ConnectionManager.instances.get(peerId); - if (!instance) { - instance = new ConnectionManager( - libp2p, - keepAliveOptions, - pubsubTopics, - relay, - options - ); - ConnectionManager.instances.set(peerId, instance); - } - - return instance; - } - public stop(): void { this.keepAliveManager.stopAll(); this.libp2p.removeEventListener( @@ -156,27 +143,21 @@ export class ConnectionManager }; } - private constructor( - libp2p: Libp2p, - keepAliveOptions: KeepAliveOptions, - public readonly configuredPubsubTopics: PubsubTopic[], - relay?: IRelay, - options?: Partial - ) { + public constructor(options: ConnectionManagerConstructorOptions) { super(); - this.libp2p = libp2p; - this.configuredPubsubTopics = configuredPubsubTopics; + this.libp2p = options.libp2p; + this.pubsubTopics = options.pubsubTopics; this.options = { maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER, maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED, maxParallelDials: DEFAULT_MAX_PARALLEL_DIALS, - ...options + ...options.config }; this.keepAliveManager = new KeepAliveManager({ - relay, - libp2p, - options: keepAliveOptions + relay: options.relay, + libp2p: options.libp2p, + options: options.keepAliveOptions }); this.startEventListeners() @@ -478,7 +459,7 @@ export class ConnectionManager log.warn( `Discovered peer ${peerId.toString()} with ShardInfo ${shardInfo} is not part of any of the configured pubsub topics (${ - this.configuredPubsubTopics + this.pubsubTopics }). Not dialing.` ); @@ -573,7 +554,7 @@ export class ConnectionManager const pubsubTopics = shardInfoToPubsubTopics(shardInfo); const isTopicConfigured = pubsubTopics.some((topic) => - this.configuredPubsubTopics.includes(topic) + this.pubsubTopics.includes(topic) ); return isTopicConfigured; } diff --git a/packages/interfaces/src/connection_manager.ts b/packages/interfaces/src/connection_manager.ts index a8a6591fdc..1644f75140 100644 --- a/packages/interfaces/src/connection_manager.ts +++ b/packages/interfaces/src/connection_manager.ts @@ -63,7 +63,7 @@ export interface IConnectionStateEvents { export interface IConnectionManager extends TypedEventEmitter { - configuredPubsubTopics: PubsubTopic[]; + pubsubTopics: PubsubTopic[]; dropConnection(peerId: PeerId): Promise; getPeersByDiscovery(): Promise; stop(): void; diff --git a/packages/sdk/src/protocols/filter/index.ts b/packages/sdk/src/protocols/filter/index.ts index 2d8f356150..d5509c2337 100644 --- a/packages/sdk/src/protocols/filter/index.ts +++ b/packages/sdk/src/protocols/filter/index.ts @@ -56,7 +56,7 @@ class Filter extends BaseProtocolSDK implements IFilter { await subscription.processIncomingMessage(wakuMessage, peerIdStr); }, - connectionManager.configuredPubsubTopics, + connectionManager.pubsubTopics, libp2p ), connectionManager, diff --git a/packages/sdk/src/protocols/light_push/light_push.ts b/packages/sdk/src/protocols/light_push/light_push.ts index 9764111f18..5919822656 100644 --- a/packages/sdk/src/protocols/light_push/light_push.ts +++ b/packages/sdk/src/protocols/light_push/light_push.ts @@ -41,10 +41,7 @@ export class LightPush implements ILightPush { options?: ProtocolCreateOptions ) { this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE; - this.protocol = new LightPushCore( - connectionManager.configuredPubsubTopics, - libp2p - ); + this.protocol = new LightPushCore(connectionManager.pubsubTopics, libp2p); } public async send( diff --git a/packages/sdk/src/protocols/store/index.ts b/packages/sdk/src/protocols/store/index.ts index 01ef45d58c..322e34f6d3 100644 --- a/packages/sdk/src/protocols/store/index.ts +++ b/packages/sdk/src/protocols/store/index.ts @@ -25,7 +25,7 @@ export class Store extends BaseProtocolSDK implements IStore { public constructor(connectionManager: ConnectionManager, libp2p: Libp2p) { super( - new StoreCore(connectionManager.configuredPubsubTopics, libp2p), + new StoreCore(connectionManager.pubsubTopics, libp2p), connectionManager, { numPeersToUse: DEFAULT_NUM_PEERS diff --git a/packages/sdk/src/waku/waku.ts b/packages/sdk/src/waku/waku.ts index eea596d7a9..b97244950d 100644 --- a/packages/sdk/src/waku/waku.ts +++ b/packages/sdk/src/waku/waku.ts @@ -95,13 +95,12 @@ export class WakuNode implements IWaku { const peerId = this.libp2p.peerId.toString(); - this.connectionManager = ConnectionManager.create( - peerId, + this.connectionManager = new ConnectionManager({ libp2p, - { pingKeepAlive, relayKeepAlive }, - this.pubsubTopics, - this.relay - ); + keepAliveOptions: { pingKeepAlive, relayKeepAlive }, + pubsubTopics: this.pubsubTopics, + relay: this.relay + }); this.health = getHealthManager(); From a6dd49974cc179dbb5f047446039db45f706fd51 Mon Sep 17 00:00:00 2001 From: Sasha Date: Sat, 19 Oct 2024 18:05:24 +0200 Subject: [PATCH 03/12] reform connection manager configurations --- packages/core/src/lib/connection_manager.ts | 18 ++++++---- packages/core/src/lib/keep_alive_manager.ts | 8 +++-- packages/interfaces/src/connection_manager.ts | 36 +++++++++++++++---- packages/interfaces/src/index.ts | 1 - packages/interfaces/src/keep_alive_manager.ts | 4 --- packages/interfaces/src/protocols.ts | 15 +++++++- packages/sdk/src/waku/waku.ts | 26 ++------------ 7 files changed, 63 insertions(+), 45 deletions(-) delete mode 100644 packages/interfaces/src/keep_alive_manager.ts diff --git a/packages/core/src/lib/connection_manager.ts b/packages/core/src/lib/connection_manager.ts index fda6ff06bb..d8697784f9 100644 --- a/packages/core/src/lib/connection_manager.ts +++ b/packages/core/src/lib/connection_manager.ts @@ -10,7 +10,6 @@ import { IConnectionStateEvents, IPeersByDiscoveryEvents, IRelay, - KeepAliveOptions, PeersByDiscoveryResult, PubsubTopic, ShardInfo @@ -23,13 +22,15 @@ import { KeepAliveManager } from "./keep_alive_manager.js"; const log = new Logger("connection-manager"); -export const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1; -export const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3; -export const DEFAULT_MAX_PARALLEL_DIALS = 3; +const DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED = 1; +const DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER = 3; +const DEFAULT_MAX_PARALLEL_DIALS = 3; + +const DEFAULT_PING_KEEP_ALIVE_SEC = 5 * 60; +const DEFAULT_RELAY_KEEP_ALIVE_SEC = 5 * 60; type ConnectionManagerConstructorOptions = { libp2p: Libp2p; - keepAliveOptions: KeepAliveOptions; pubsubTopics: PubsubTopic[]; relay?: IRelay; config?: Partial; @@ -151,13 +152,18 @@ export class ConnectionManager maxDialAttemptsForPeer: DEFAULT_MAX_DIAL_ATTEMPTS_FOR_PEER, maxBootstrapPeersAllowed: DEFAULT_MAX_BOOTSTRAP_PEERS_ALLOWED, maxParallelDials: DEFAULT_MAX_PARALLEL_DIALS, + pingKeepAlive: DEFAULT_PING_KEEP_ALIVE_SEC, + relayKeepAlive: DEFAULT_RELAY_KEEP_ALIVE_SEC, ...options.config }; this.keepAliveManager = new KeepAliveManager({ relay: options.relay, libp2p: options.libp2p, - options: options.keepAliveOptions + options: { + pingKeepAlive: this.options.pingKeepAlive, + relayKeepAlive: this.options.relayKeepAlive + } }); this.startEventListeners() diff --git a/packages/core/src/lib/keep_alive_manager.ts b/packages/core/src/lib/keep_alive_manager.ts index 27754b6b38..3f606acd9b 100644 --- a/packages/core/src/lib/keep_alive_manager.ts +++ b/packages/core/src/lib/keep_alive_manager.ts @@ -1,14 +1,18 @@ import type { PeerId } from "@libp2p/interface"; import type { IRelay, Libp2p, PeerIdStr } from "@waku/interfaces"; -import type { KeepAliveOptions } from "@waku/interfaces"; import { Logger, pubsubTopicToSingleShardInfo } from "@waku/utils"; import { utf8ToBytes } from "@waku/utils/bytes"; import { createEncoder } from "./message/version_0.js"; -export const RelayPingContentTopic = "/relay-ping/1/ping/null"; +const RelayPingContentTopic = "/relay-ping/1/ping/null"; const log = new Logger("keep-alive"); +type KeepAliveOptions = { + pingKeepAlive: number; + relayKeepAlive: number; +}; + type CreateKeepAliveManagerOptions = { options: KeepAliveOptions; libp2p: Libp2p; diff --git a/packages/interfaces/src/connection_manager.ts b/packages/interfaces/src/connection_manager.ts index 1644f75140..f0810e4736 100644 --- a/packages/interfaces/src/connection_manager.ts +++ b/packages/interfaces/src/connection_manager.ts @@ -8,22 +8,44 @@ export enum Tags { LOCAL = "local-peer-cache" } -export interface ConnectionManagerOptions { +export type ConnectionManagerOptions = { /** - * Number of attempts before a peer is considered non-dialable - * This is used to not spam a peer with dial attempts when it is not dialable + * Number of attempts before a peer is considered non-dialable. + * This is used to not spam a peer with dial attempts when it is not dialable. + * + * @default 3 */ maxDialAttemptsForPeer: number; + /** - * Max number of bootstrap peers allowed to be connected to, initially - * This is used to increase intention of dialing non-bootstrap peers, found using other discovery mechanisms (like Peer Exchange) + * Max number of bootstrap peers allowed to be connected to initially. + * This is used to increase intention of dialing non-bootstrap peers, found using other discovery mechanisms (like Peer Exchange). + * + * @default 1 */ maxBootstrapPeersAllowed: number; + /** - * Max number of parallel dials allowed + * Max number of parallel dials allowed. + * + * @default 3 */ maxParallelDials: number; -} + + /** + * Keep alive libp2p pings interval in seconds. + * + * @default 300 seconds + */ + pingKeepAlive: number; + + /** + * Gossip sub specific keep alive interval in seconds. + * + * @default 300 seconds + */ + relayKeepAlive: number; +}; export enum EPeersByDiscoveryEvents { PEER_DISCOVERY_BOOTSTRAP = "peer:discovery:bootstrap", diff --git a/packages/interfaces/src/index.ts b/packages/interfaces/src/index.ts index 8cfe38114f..ed2cb5240a 100644 --- a/packages/interfaces/src/index.ts +++ b/packages/interfaces/src/index.ts @@ -12,7 +12,6 @@ export * from "./sender.js"; export * from "./receiver.js"; export * from "./misc.js"; export * from "./libp2p.js"; -export * from "./keep_alive_manager.js"; export * from "./dns_discovery.js"; export * from "./metadata.js"; export * from "./constants.js"; diff --git a/packages/interfaces/src/keep_alive_manager.ts b/packages/interfaces/src/keep_alive_manager.ts deleted file mode 100644 index f6d7791d10..0000000000 --- a/packages/interfaces/src/keep_alive_manager.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface KeepAliveOptions { - pingKeepAlive: number; - relayKeepAlive: number; -} diff --git a/packages/interfaces/src/protocols.ts b/packages/interfaces/src/protocols.ts index 74462efa13..e18ca6592a 100644 --- a/packages/interfaces/src/protocols.ts +++ b/packages/interfaces/src/protocols.ts @@ -2,6 +2,7 @@ import type { Libp2p } from "@libp2p/interface"; import type { PeerId } from "@libp2p/interface"; import type { Peer } from "@libp2p/interface"; +import type { ConnectionManagerOptions } from "./connection_manager.js"; import type { CreateLibp2pOptions } from "./libp2p.js"; import type { IDecodedMessage } from "./message.js"; import { ThisAndThat, ThisOrThat } from "./misc.js"; @@ -58,6 +59,7 @@ export type ProtocolCreateOptions = { * See [Waku v2 Topic Usage Recommendations](https://github.com/vacp2p/rfc-index/blob/main/waku/informational/23/topics.md#content-topics) for details. * You cannot add or remove content topics after initialization of the node. */ + /** * Configuration for determining the network in use. * Network configuration refers to the shards and clusters used in the network. @@ -76,6 +78,7 @@ export type ProtocolCreateOptions = { * @default { clusterId: 1, shards: [0, 1, 2, 3, 4, 5, 6, 7] } */ networkConfig?: NetworkConfig; + /** * You can pass options to the `Libp2p` instance used by {@link @waku/sdk!WakuNode} using the `libp2p` property. * This property is the same type as the one passed to [`Libp2p.create`](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md#create) @@ -84,28 +87,38 @@ export type ProtocolCreateOptions = { * Notes that some values are overridden by {@link @waku/sdk!WakuNode} to ensure it implements the Waku protocol. */ libp2p?: Partial; + /** * Number of peers to connect to, for the usage of the protocol. * This is used by: * - Light Push to send messages, * - Filter to retrieve messages. - * Defaults to 2. + * + * @default 2. */ numPeersToUse?: number; + /** * Byte array used as key for the noise protocol used for connection encryption * by [`Libp2p.create`](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md#create) * This is only used for test purposes to not run out of entropy during CI runs. */ staticNoiseKey?: Uint8Array; + /** * Use recommended bootstrap method to discovery and connect to new nodes. */ defaultBootstrap?: boolean; + /** * List of peers to use to bootstrap the node. Ignored if defaultBootstrap is set to true. */ bootstrapPeers?: string[]; + + /** + * Configuration for connection manager. If not specified - default values are applied. + */ + connectionManager?: Partial; }; export type Callback = ( diff --git a/packages/sdk/src/waku/waku.ts b/packages/sdk/src/waku/waku.ts index b97244950d..0f492857b0 100644 --- a/packages/sdk/src/waku/waku.ts +++ b/packages/sdk/src/waku/waku.ts @@ -23,28 +23,12 @@ import { ReliabilityMonitorManager } from "../reliability_monitor/index.js"; import { waitForRemotePeer } from "./wait_for_remote_peer.js"; -export const DefaultPingKeepAliveValueSecs = 5 * 60; -export const DefaultRelayKeepAliveValueSecs = 5 * 60; export const DefaultUserAgent = "js-waku"; export const DefaultPingMaxInboundStreams = 10; const log = new Logger("waku"); export interface WakuOptions { - /** - * Set keep alive frequency in seconds: Waku will send a `/ipfs/ping/1.0.0` - * request to each peer after the set number of seconds. Set to 0 to disable. - * - * @default {@link @waku/core.DefaultPingKeepAliveValueSecs} - */ - pingKeepAlive?: number; - /** - * Set keep alive frequency in seconds: Waku will send a ping message over - * relay to each peer after the set number of seconds. Set to 0 to disable. - * - * @default {@link @waku/core.DefaultRelayKeepAliveValueSecs} - */ - relayKeepAlive?: number; /** * Set the user agent string to be used in identification of the node. * @default {@link @waku/core.DefaultUserAgent} @@ -87,19 +71,13 @@ export class WakuNode implements IWaku { ...protocolsEnabled }; - const pingKeepAlive = - options.pingKeepAlive || DefaultPingKeepAliveValueSecs; - const relayKeepAlive = this.relay - ? options.relayKeepAlive || DefaultRelayKeepAliveValueSecs - : 0; - const peerId = this.libp2p.peerId.toString(); this.connectionManager = new ConnectionManager({ libp2p, - keepAliveOptions: { pingKeepAlive, relayKeepAlive }, + relay: this.relay, pubsubTopics: this.pubsubTopics, - relay: this.relay + config: options?.connectionManager }); this.health = getHealthManager(); From e897d5cd6f69e9fcfa080c1cf02639f3229cf03f Mon Sep 17 00:00:00 2001 From: Sasha Date: Sun, 20 Oct 2024 16:02:12 +0200 Subject: [PATCH 04/12] remove log param from peerManager --- packages/sdk/src/protocols/base_protocol.ts | 2 +- packages/sdk/src/protocols/peer_manager.ts | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/sdk/src/protocols/base_protocol.ts b/packages/sdk/src/protocols/base_protocol.ts index 3ef5cc1df8..72295b2747 100644 --- a/packages/sdk/src/protocols/base_protocol.ts +++ b/packages/sdk/src/protocols/base_protocol.ts @@ -33,7 +33,7 @@ export class BaseProtocolSDK implements IBaseProtocolSDK { const maintainPeersInterval = options?.maintainPeersInterval ?? DEFAULT_MAINTAIN_PEERS_INTERVAL; - this.peerManager = new PeerManager(connectionManager, core, this.log); + this.peerManager = new PeerManager(connectionManager, core); this.log.info( `Initializing BaseProtocolSDK with numPeersToUse: ${this.numPeersToUse}, maintainPeersInterval: ${maintainPeersInterval}ms` diff --git a/packages/sdk/src/protocols/peer_manager.ts b/packages/sdk/src/protocols/peer_manager.ts index dcdc024f1b..422f508e15 100644 --- a/packages/sdk/src/protocols/peer_manager.ts +++ b/packages/sdk/src/protocols/peer_manager.ts @@ -5,6 +5,8 @@ import { IHealthManager } from "@waku/interfaces"; import { Logger } from "@waku/utils"; import { Mutex } from "async-mutex"; +const log = new Logger("peer-manager"); + export class PeerManager { private peers: Map = new Map(); private healthManager: IHealthManager; @@ -15,8 +17,7 @@ export class PeerManager { public constructor( private readonly connectionManager: ConnectionManager, - private readonly core: BaseProtocol, - private readonly log: Logger + private readonly core: BaseProtocol ) { this.healthManager = getHealthManager(); this.healthManager.updateProtocolHealth(this.core.multicodec, 0); @@ -35,7 +36,7 @@ export class PeerManager { this.writeLockHolder = `addPeer: ${peer.id.toString()}`; await this.connectionManager.attemptDial(peer.id); this.peers.set(peer.id.toString(), peer); - this.log.info(`Added and dialed peer: ${peer.id.toString()}`); + log.info(`Added and dialed peer: ${peer.id.toString()}`); this.healthManager.updateProtocolHealth( this.core.multicodec, this.peers.size @@ -48,7 +49,7 @@ export class PeerManager { return this.writeMutex.runExclusive(() => { this.writeLockHolder = `removePeer: ${peerId.toString()}`; this.peers.delete(peerId.toString()); - this.log.info(`Removed peer: ${peerId.toString()}`); + log.info(`Removed peer: ${peerId.toString()}`); this.healthManager.updateProtocolHealth( this.core.multicodec, this.peers.size @@ -66,7 +67,7 @@ export class PeerManager { } public async removeExcessPeers(excessPeers: number): Promise { - this.log.info(`Removing ${excessPeers} excess peer(s)`); + log.info(`Removing ${excessPeers} excess peer(s)`); const peersToRemove = Array.from(this.peers.values()).slice(0, excessPeers); for (const peer of peersToRemove) { await this.removePeer(peer.id); @@ -80,7 +81,7 @@ export class PeerManager { public async findAndAddPeers(numPeers: number): Promise { const additionalPeers = await this.findPeers(numPeers); if (additionalPeers.length === 0) { - this.log.warn("No additional peers found"); + log.warn("No additional peers found"); return []; } return this.addMultiplePeers(additionalPeers); From e1813bc47b9f70124e7b4ec76cccb4596bbfd1c1 Mon Sep 17 00:00:00 2001 From: Sasha Date: Sun, 20 Oct 2024 22:54:36 +0200 Subject: [PATCH 05/12] make PeerManager use only ConnectionManager, move getPeers to ConnectionManager, remove not needed code --- packages/core/src/index.ts | 3 +- packages/core/src/lib/base_protocol.ts | 55 +-- .../connection_manager.ts | 24 ++ .../core/src/lib/connection_manager/index.ts | 1 + .../keep_alive_manager.ts | 2 +- .../core/src/lib/connection_manager/utils.ts | 25 ++ packages/core/src/lib/filter/index.ts | 2 +- packages/core/src/lib/filterPeers.spec.ts | 144 -------- packages/core/src/lib/filterPeers.ts | 51 --- packages/core/src/lib/light_push/index.ts | 2 +- packages/core/src/lib/metadata/index.ts | 2 +- packages/core/src/lib/store/index.ts | 2 +- .../src/peer-exchange/waku_peer_exchange.ts | 2 +- packages/interfaces/src/connection_manager.ts | 1 + packages/sdk/src/protocols/base_protocol.ts | 2 +- .../src/protocols/light_push/light_push.ts | 27 +- packages/sdk/src/protocols/peer_manager.ts | 23 +- packages/sdk/src/protocols/store/index.ts | 11 +- packages/tests/tests/getPeers.spec.ts | 339 ------------------ packages/utils/src/libp2p/index.ts | 38 -- 20 files changed, 73 insertions(+), 683 deletions(-) rename packages/core/src/lib/{ => connection_manager}/connection_manager.ts (96%) create mode 100644 packages/core/src/lib/connection_manager/index.ts rename packages/core/src/lib/{ => connection_manager}/keep_alive_manager.ts (98%) create mode 100644 packages/core/src/lib/connection_manager/utils.ts delete mode 100644 packages/core/src/lib/filterPeers.spec.ts delete mode 100644 packages/core/src/lib/filterPeers.ts delete mode 100644 packages/tests/tests/getPeers.spec.ts diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 9b4acf2eae..cd9f894730 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -15,11 +15,10 @@ export { LightPushCodec, LightPushCore } from "./lib/light_push/index.js"; export * as waku_store from "./lib/store/index.js"; export { StoreCore, StoreCodec } from "./lib/store/index.js"; -export { ConnectionManager } from "./lib/connection_manager.js"; +export { ConnectionManager } from "./lib/connection_manager/index.js"; export { getHealthManager } from "./lib/health_manager.js"; -export { KeepAliveManager } from "./lib/keep_alive_manager.js"; export { StreamManager } from "./lib/stream_manager/index.js"; export { MetadataCodec, wakuMetadata } from "./lib/metadata/index.js"; diff --git a/packages/core/src/lib/base_protocol.ts b/packages/core/src/lib/base_protocol.ts index 740298ae0a..b8ed44e8d0 100644 --- a/packages/core/src/lib/base_protocol.ts +++ b/packages/core/src/lib/base_protocol.ts @@ -5,10 +5,8 @@ import type { Libp2pComponents, PubsubTopic } from "@waku/interfaces"; -import { Logger } from "@waku/utils"; -import { getPeersForProtocol, sortPeersByLatency } from "@waku/utils/libp2p"; +import { getPeersForProtocol } from "@waku/utils/libp2p"; -import { filterPeersByDiscovery } from "./filterPeers.js"; import { StreamManager } from "./stream_manager/index.js"; /** @@ -23,7 +21,6 @@ export class BaseProtocol implements IBaseProtocolCore { protected constructor( public multicodec: string, protected components: Libp2pComponents, - private log: Logger, public readonly pubsubTopics: PubsubTopic[] ) { this.addLibp2pEventListener = components.events.addEventListener.bind( @@ -64,54 +61,4 @@ export class BaseProtocol implements IBaseProtocolCore { return connections.length > 0; }); } - - /** - * Retrieves a list of connected peers that support the protocol. The list is sorted by latency. - * - * @param numPeers - The total number of peers to retrieve. If 0, all peers are returned. - * @param maxBootstrapPeers - The maximum number of bootstrap peers to retrieve. - * @returns A list of peers that support the protocol sorted by latency. By default, returns all peers available, including bootstrap. - */ - public async getPeers( - { - numPeers, - maxBootstrapPeers - }: { - numPeers: number; - maxBootstrapPeers: number; - } = { - maxBootstrapPeers: 0, - numPeers: 0 - } - ): Promise { - // Retrieve all connected peers that support the protocol & shard (if configured) - const allAvailableConnectedPeers = await this.connectedPeers(); - - // Filter the peers based on discovery & number of peers requested - const filteredPeers = filterPeersByDiscovery( - allAvailableConnectedPeers, - numPeers, - maxBootstrapPeers - ); - - // Sort the peers by latency - const sortedFilteredPeers = await sortPeersByLatency( - this.components.peerStore, - filteredPeers - ); - - if (sortedFilteredPeers.length === 0) { - this.log.warn( - "No peers found. Ensure you have a connection to the network." - ); - } - - if (sortedFilteredPeers.length < numPeers) { - this.log.warn( - `Only ${sortedFilteredPeers.length} peers found. Requested ${numPeers}.` - ); - } - - return sortedFilteredPeers; - } } diff --git a/packages/core/src/lib/connection_manager.ts b/packages/core/src/lib/connection_manager/connection_manager.ts similarity index 96% rename from packages/core/src/lib/connection_manager.ts rename to packages/core/src/lib/connection_manager/connection_manager.ts index d8697784f9..4f482d4822 100644 --- a/packages/core/src/lib/connection_manager.ts +++ b/packages/core/src/lib/connection_manager/connection_manager.ts @@ -19,6 +19,7 @@ import { decodeRelayShard, shardInfoToPubsubTopics } from "@waku/utils"; import { Logger } from "@waku/utils"; import { KeepAliveManager } from "./keep_alive_manager.js"; +import { getPeerPing } from "./utils.js"; const log = new Logger("connection-manager"); @@ -180,6 +181,29 @@ export class ConnectionManager ); } + public async getConnectedPeers(codec?: string): Promise { + const peerIDs = this.libp2p.getPeers(); + + if (peerIDs.length === 0) { + return []; + } + + const peers = await Promise.all( + peerIDs.map(async (id) => { + try { + return await this.libp2p.peerStore.get(id); + } catch (e) { + return null; + } + }) + ); + + return peers + .filter((p) => !!p) + .filter((p) => (codec ? (p as Peer).protocols.includes(codec) : true)) + .sort((left, right) => getPeerPing(left) - getPeerPing(right)) as Peer[]; + } + private async dialPeerStorePeers(): Promise { const peerInfos = await this.libp2p.peerStore.all(); const dialPromises = []; diff --git a/packages/core/src/lib/connection_manager/index.ts b/packages/core/src/lib/connection_manager/index.ts new file mode 100644 index 0000000000..b5e0c20d00 --- /dev/null +++ b/packages/core/src/lib/connection_manager/index.ts @@ -0,0 +1 @@ +export { ConnectionManager } from "./connection_manager.js"; diff --git a/packages/core/src/lib/keep_alive_manager.ts b/packages/core/src/lib/connection_manager/keep_alive_manager.ts similarity index 98% rename from packages/core/src/lib/keep_alive_manager.ts rename to packages/core/src/lib/connection_manager/keep_alive_manager.ts index 3f606acd9b..266a94da39 100644 --- a/packages/core/src/lib/keep_alive_manager.ts +++ b/packages/core/src/lib/connection_manager/keep_alive_manager.ts @@ -3,7 +3,7 @@ import type { IRelay, Libp2p, PeerIdStr } from "@waku/interfaces"; import { Logger, pubsubTopicToSingleShardInfo } from "@waku/utils"; import { utf8ToBytes } from "@waku/utils/bytes"; -import { createEncoder } from "./message/version_0.js"; +import { createEncoder } from "../message/version_0.js"; const RelayPingContentTopic = "/relay-ping/1/ping/null"; const log = new Logger("keep-alive"); diff --git a/packages/core/src/lib/connection_manager/utils.ts b/packages/core/src/lib/connection_manager/utils.ts new file mode 100644 index 0000000000..b994e1df7c --- /dev/null +++ b/packages/core/src/lib/connection_manager/utils.ts @@ -0,0 +1,25 @@ +import type { Peer } from "@libp2p/interface"; +import { bytesToUtf8 } from "@waku/utils/bytes"; + +/** + * Reads peer's metadata and retrieves ping value. + * @param peer Peer or null + * @returns -1 if no ping attached, otherwise returns ping value + */ +export const getPeerPing = (peer: Peer | null): number => { + if (!peer) { + return -1; + } + + try { + const bytes = peer.metadata.get("ping"); + + if (!bytes) { + return -1; + } + + return Number(bytesToUtf8(bytes)); + } catch (e) { + return -1; + } +}; diff --git a/packages/core/src/lib/filter/index.ts b/packages/core/src/lib/filter/index.ts index 06e57cfe1c..09bbef9e62 100644 --- a/packages/core/src/lib/filter/index.ts +++ b/packages/core/src/lib/filter/index.ts @@ -40,7 +40,7 @@ export class FilterCore extends BaseProtocol implements IBaseProtocolCore { public readonly pubsubTopics: PubsubTopic[], libp2p: Libp2p ) { - super(FilterCodecs.SUBSCRIBE, libp2p.components, log, pubsubTopics); + super(FilterCodecs.SUBSCRIBE, libp2p.components, pubsubTopics); libp2p .handle(FilterCodecs.PUSH, this.onRequest.bind(this), { diff --git a/packages/core/src/lib/filterPeers.spec.ts b/packages/core/src/lib/filterPeers.spec.ts deleted file mode 100644 index 8ae77c3bd2..0000000000 --- a/packages/core/src/lib/filterPeers.spec.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { Peer } from "@libp2p/interface"; -import type { Tag } from "@libp2p/interface"; -import { createSecp256k1PeerId } from "@libp2p/peer-id-factory"; -import { Tags } from "@waku/interfaces"; -import { expect } from "chai"; - -import { filterPeersByDiscovery } from "./filterPeers.js"; - -describe("filterPeersByDiscovery function", function () { - it("should return all peers when numPeers is 0", async function () { - const peer1 = await createSecp256k1PeerId(); - const peer2 = await createSecp256k1PeerId(); - const peer3 = await createSecp256k1PeerId(); - - const mockPeers = [ - { - id: peer1, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer2, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer3, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - } - ] as unknown as Peer[]; - - const result = filterPeersByDiscovery(mockPeers, 0, 10); - expect(result.length).to.deep.equal(mockPeers.length); - }); - - it("should return all non-bootstrap peers and no bootstrap peer when numPeers is 0 and maxBootstrapPeers is 0", async function () { - const peer1 = await createSecp256k1PeerId(); - const peer2 = await createSecp256k1PeerId(); - const peer3 = await createSecp256k1PeerId(); - const peer4 = await createSecp256k1PeerId(); - - const mockPeers = [ - { - id: peer1, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer2, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer3, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - }, - { - id: peer4, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - } - ] as unknown as Peer[]; - - const result = filterPeersByDiscovery(mockPeers, 0, 0); - - // result should have no bootstrap peers, and a total of 2 peers - expect(result.length).to.equal(2); - expect( - result.filter((peer: Peer) => peer.tags.has(Tags.BOOTSTRAP)).length - ).to.equal(0); - }); - - it("should return one bootstrap peer, and all non-boostrap peers, when numPeers is 0 & maxBootstrap is 1", async function () { - const peer1 = await createSecp256k1PeerId(); - const peer2 = await createSecp256k1PeerId(); - const peer3 = await createSecp256k1PeerId(); - const peer4 = await createSecp256k1PeerId(); - const peer5 = await createSecp256k1PeerId(); - - const mockPeers = [ - { - id: peer1, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer2, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer3, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - }, - { - id: peer4, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - }, - { - id: peer5, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - } - ] as unknown as Peer[]; - - const result = filterPeersByDiscovery(mockPeers, 0, 1); - - // result should have 1 bootstrap peers, and a total of 4 peers - expect(result.length).to.equal(4); - expect( - result.filter((peer: Peer) => peer.tags.has(Tags.BOOTSTRAP)).length - ).to.equal(1); - }); - - it("should return only bootstrap peers up to maxBootstrapPeers", async function () { - const peer1 = await createSecp256k1PeerId(); - const peer2 = await createSecp256k1PeerId(); - const peer3 = await createSecp256k1PeerId(); - const peer4 = await createSecp256k1PeerId(); - const peer5 = await createSecp256k1PeerId(); - - const mockPeers = [ - { - id: peer1, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer2, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer3, - tags: new Map([[Tags.BOOTSTRAP, { value: 100 }]]) - }, - { - id: peer4, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - }, - { - id: peer5, - tags: new Map([[Tags.PEER_EXCHANGE, { value: 100 }]]) - } - ] as unknown as Peer[]; - - const result = filterPeersByDiscovery(mockPeers, 5, 2); - - // check that result has at least 2 bootstrap peers and no more than 5 peers - expect(result.length).to.be.at.least(2); - expect(result.length).to.be.at.most(5); - expect(result.filter((peer: Peer) => peer.tags.has(Tags.BOOTSTRAP)).length); - }); -}); diff --git a/packages/core/src/lib/filterPeers.ts b/packages/core/src/lib/filterPeers.ts deleted file mode 100644 index 816c3bd5b5..0000000000 --- a/packages/core/src/lib/filterPeers.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Peer } from "@libp2p/interface"; -import { Tags } from "@waku/interfaces"; - -/** - * Retrieves a list of peers based on the specified criteria: - * 1. If numPeers is 0, return all peers - * 2. Bootstrap peers are prioritized - * 3. Non-bootstrap peers are randomly selected to fill up to numPeers - * - * @param peers - The list of peers to filter from. - * @param numPeers - The total number of peers to retrieve. If 0, all peers are returned, irrespective of `maxBootstrapPeers`. - * @param maxBootstrapPeers - The maximum number of bootstrap peers to retrieve. - * @returns An array of peers based on the specified criteria. - */ -export function filterPeersByDiscovery( - peers: Peer[], - numPeers: number, - maxBootstrapPeers: number -): Peer[] { - // Collect the bootstrap peers up to the specified maximum - let bootstrapPeers = peers - .filter((peer) => peer.tags.has(Tags.BOOTSTRAP)) - .slice(0, maxBootstrapPeers); - - // If numPeers is less than the number of bootstrap peers, adjust the bootstrapPeers array - if (numPeers > 0 && numPeers < bootstrapPeers.length) { - bootstrapPeers = bootstrapPeers.slice(0, numPeers); - } - - // Collect non-bootstrap peers - const nonBootstrapPeers = peers.filter( - (peer) => !peer.tags.has(Tags.BOOTSTRAP) - ); - - // If numPeers is 0, return all peers - if (numPeers === 0) { - return [...bootstrapPeers, ...nonBootstrapPeers]; - } - - // Initialize the list of selected peers with the bootstrap peers - const selectedPeers: Peer[] = [...bootstrapPeers]; - - // Fill up to numPeers with remaining random peers if needed - while (selectedPeers.length < numPeers && nonBootstrapPeers.length > 0) { - const randomIndex = Math.floor(Math.random() * nonBootstrapPeers.length); - const randomPeer = nonBootstrapPeers.splice(randomIndex, 1)[0]; - selectedPeers.push(randomPeer); - } - - return selectedPeers; -} diff --git a/packages/core/src/lib/light_push/index.ts b/packages/core/src/lib/light_push/index.ts index e807bee5ad..440201464f 100644 --- a/packages/core/src/lib/light_push/index.ts +++ b/packages/core/src/lib/light_push/index.ts @@ -37,7 +37,7 @@ export class LightPushCore extends BaseProtocol implements IBaseProtocolCore { public readonly pubsubTopics: PubsubTopic[], libp2p: Libp2p ) { - super(LightPushCodec, libp2p.components, log, pubsubTopics); + super(LightPushCodec, libp2p.components, pubsubTopics); } private async preparePushMessage( diff --git a/packages/core/src/lib/metadata/index.ts b/packages/core/src/lib/metadata/index.ts index 1744450c7b..2b3bfe2532 100644 --- a/packages/core/src/lib/metadata/index.ts +++ b/packages/core/src/lib/metadata/index.ts @@ -30,7 +30,7 @@ class Metadata extends BaseProtocol implements IMetadata { public pubsubTopics: PubsubTopic[], libp2p: Libp2pComponents ) { - super(MetadataCodec, libp2p.components, log, pubsubTopics); + super(MetadataCodec, libp2p.components, pubsubTopics); this.libp2pComponents = libp2p; void libp2p.registrar.handle(MetadataCodec, (streamData) => { void this.onRequest(streamData); diff --git a/packages/core/src/lib/store/index.ts b/packages/core/src/lib/store/index.ts index a4b8b9c2e7..830a7b5100 100644 --- a/packages/core/src/lib/store/index.ts +++ b/packages/core/src/lib/store/index.ts @@ -32,7 +32,7 @@ export class StoreCore extends BaseProtocol implements IStoreCore { public readonly pubsubTopics: PubsubTopic[], libp2p: Libp2p ) { - super(StoreCodec, libp2p.components, log, pubsubTopics); + super(StoreCodec, libp2p.components, pubsubTopics); } public async *queryPerPage( diff --git a/packages/discovery/src/peer-exchange/waku_peer_exchange.ts b/packages/discovery/src/peer-exchange/waku_peer_exchange.ts index 6030b86f76..43520e9bde 100644 --- a/packages/discovery/src/peer-exchange/waku_peer_exchange.ts +++ b/packages/discovery/src/peer-exchange/waku_peer_exchange.ts @@ -32,7 +32,7 @@ export class WakuPeerExchange extends BaseProtocol implements IPeerExchange { components: Libp2pComponents, pubsubTopics: PubsubTopic[] ) { - super(PeerExchangeCodec, components, log, pubsubTopics); + super(PeerExchangeCodec, components, pubsubTopics); } /** diff --git a/packages/interfaces/src/connection_manager.ts b/packages/interfaces/src/connection_manager.ts index f0810e4736..8610acab95 100644 --- a/packages/interfaces/src/connection_manager.ts +++ b/packages/interfaces/src/connection_manager.ts @@ -86,6 +86,7 @@ export interface IConnectionStateEvents { export interface IConnectionManager extends TypedEventEmitter { pubsubTopics: PubsubTopic[]; + getConnectedPeers(codec?: string): Promise; dropConnection(peerId: PeerId): Promise; getPeersByDiscovery(): Promise; stop(): void; diff --git a/packages/sdk/src/protocols/base_protocol.ts b/packages/sdk/src/protocols/base_protocol.ts index 72295b2747..3a7abc1b36 100644 --- a/packages/sdk/src/protocols/base_protocol.ts +++ b/packages/sdk/src/protocols/base_protocol.ts @@ -33,7 +33,7 @@ export class BaseProtocolSDK implements IBaseProtocolSDK { const maintainPeersInterval = options?.maintainPeersInterval ?? DEFAULT_MAINTAIN_PEERS_INTERVAL; - this.peerManager = new PeerManager(connectionManager, core); + this.peerManager = new PeerManager(connectionManager); this.log.info( `Initializing BaseProtocolSDK with numPeersToUse: ${this.numPeersToUse}, maintainPeersInterval: ${maintainPeersInterval}ms` diff --git a/packages/sdk/src/protocols/light_push/light_push.ts b/packages/sdk/src/protocols/light_push/light_push.ts index 5919822656..478e683b7d 100644 --- a/packages/sdk/src/protocols/light_push/light_push.ts +++ b/packages/sdk/src/protocols/light_push/light_push.ts @@ -36,8 +36,8 @@ export class LightPush implements ILightPush { public readonly protocol: LightPushCore; public constructor( - connectionManager: ConnectionManager, - private libp2p: Libp2p, + private connectionManager: ConnectionManager, + libp2p: Libp2p, options?: ProtocolCreateOptions ) { this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE; @@ -147,26 +147,9 @@ export class LightPush implements ILightPush { } private async getConnectedPeers(): Promise { - const peerIDs = this.libp2p.getPeers(); - - if (peerIDs.length === 0) { - return []; - } - - const peers = await Promise.all( - peerIDs.map(async (id) => { - try { - return await this.libp2p.peerStore.get(id); - } catch (e) { - return null; - } - }) - ); - - return peers - .filter((p) => !!p) - .filter((p) => (p as Peer).protocols.includes(LightPushCodec)) - .slice(0, this.numPeersToUse) as Peer[]; + const peers = + await this.connectionManager.getConnectedPeers(LightPushCodec); + return peers.slice(0, this.numPeersToUse); } } diff --git a/packages/sdk/src/protocols/peer_manager.ts b/packages/sdk/src/protocols/peer_manager.ts index 422f508e15..d8bf25f0bc 100644 --- a/packages/sdk/src/protocols/peer_manager.ts +++ b/packages/sdk/src/protocols/peer_manager.ts @@ -1,7 +1,5 @@ import { Peer, PeerId } from "@libp2p/interface"; -import { ConnectionManager, getHealthManager } from "@waku/core"; -import { BaseProtocol } from "@waku/core/lib/base_protocol"; -import { IHealthManager } from "@waku/interfaces"; +import { ConnectionManager } from "@waku/core"; import { Logger } from "@waku/utils"; import { Mutex } from "async-mutex"; @@ -9,19 +7,12 @@ const log = new Logger("peer-manager"); export class PeerManager { private peers: Map = new Map(); - private healthManager: IHealthManager; private readMutex = new Mutex(); private writeMutex = new Mutex(); private writeLockHolder: string | null = null; - public constructor( - private readonly connectionManager: ConnectionManager, - private readonly core: BaseProtocol - ) { - this.healthManager = getHealthManager(); - this.healthManager.updateProtocolHealth(this.core.multicodec, 0); - } + public constructor(private readonly connectionManager: ConnectionManager) {} public getWriteLockHolder(): string | null { return this.writeLockHolder; @@ -37,10 +28,6 @@ export class PeerManager { await this.connectionManager.attemptDial(peer.id); this.peers.set(peer.id.toString(), peer); log.info(`Added and dialed peer: ${peer.id.toString()}`); - this.healthManager.updateProtocolHealth( - this.core.multicodec, - this.peers.size - ); this.writeLockHolder = null; }); } @@ -50,10 +37,6 @@ export class PeerManager { this.writeLockHolder = `removePeer: ${peerId.toString()}`; this.peers.delete(peerId.toString()); log.info(`Removed peer: ${peerId.toString()}`); - this.healthManager.updateProtocolHealth( - this.core.multicodec, - this.peers.size - ); this.writeLockHolder = null; }); } @@ -92,7 +75,7 @@ export class PeerManager { * @param numPeers The number of peers to find. */ public async findPeers(numPeers: number): Promise { - const connectedPeers = await this.core.getPeers(); + const connectedPeers = await this.connectionManager.getConnectedPeers(); return this.readMutex.runExclusive(async () => { const newPeers = connectedPeers diff --git a/packages/sdk/src/protocols/store/index.ts b/packages/sdk/src/protocols/store/index.ts index 322e34f6d3..efd58033f8 100644 --- a/packages/sdk/src/protocols/store/index.ts +++ b/packages/sdk/src/protocols/store/index.ts @@ -58,12 +58,11 @@ export class Store extends BaseProtocolSDK implements IStore { ...options }; - const peer = ( - await this.protocol.getPeers({ - numPeers: this.numPeersToUse, - maxBootstrapPeers: 1 - }) - )[0]; + const peers = await this.connectionManager.getConnectedPeers( + this.core.multicodec + ); + const peer = peers[0]; + if (!peer) { log.error("No peers available to query"); throw new Error("No peers available to query"); diff --git a/packages/tests/tests/getPeers.spec.ts b/packages/tests/tests/getPeers.spec.ts deleted file mode 100644 index dd0ba3ad5c..0000000000 --- a/packages/tests/tests/getPeers.spec.ts +++ /dev/null @@ -1,339 +0,0 @@ -import type { Connection, Peer, PeerStore } from "@libp2p/interface"; -import { createSecp256k1PeerId } from "@libp2p/peer-id-factory"; -import { - createLightNode, - Libp2pComponents, - type LightNode, - Tags, - utf8ToBytes -} from "@waku/sdk"; -import { encodeRelayShard } from "@waku/utils"; -import { expect } from "chai"; -import fc from "fast-check"; -import Sinon from "sinon"; - -import { - afterEachCustom, - beforeEachCustom, - DefaultTestShardInfo -} from "../src/index.js"; - -describe("getPeers", function () { - let peerStore: PeerStore; - let connectionManager: Libp2pComponents["connectionManager"]; - let waku: LightNode; - const lowPingBytes = utf8ToBytes("50"); - const midPingBytes = utf8ToBytes("100"); - const highPingBytes = utf8ToBytes("200"); - - let lowPingBootstrapPeer: Peer, - lowPingNonBootstrapPeer: Peer, - midPingBootstrapPeer: Peer, - midPingNonBootstrapPeer: Peer, - highPingBootstrapPeer: Peer, - highPingNonBootstrapPeer: Peer, - differentCodecPeer: Peer, - anotherDifferentCodecPeer: Peer; - - let bootstrapPeers: Peer[]; - let nonBootstrapPeers: Peer[]; - let allPeers: Peer[]; - - beforeEachCustom(this, async () => { - waku = await createLightNode({ networkConfig: DefaultTestShardInfo }); - peerStore = waku.libp2p.peerStore; - connectionManager = waku.libp2p.components.connectionManager; - - const [ - lowPingBootstrapPeerId, - lowPingNonBootstrapPeerId, - midPingBootstrapPeerId, - midPingNonBootstrapPeerId, - highPingBootstrapPeerId, - highPingNonBootstrapPeerId, - differentCodecPeerId, - anotherDifferentCodecPeerId - ] = await Promise.all([ - createSecp256k1PeerId(), - createSecp256k1PeerId(), - createSecp256k1PeerId(), - createSecp256k1PeerId(), - createSecp256k1PeerId(), - createSecp256k1PeerId(), - createSecp256k1PeerId(), - createSecp256k1PeerId() - ]); - - lowPingBootstrapPeer = { - id: lowPingBootstrapPeerId, - protocols: [waku.lightPush.protocol.multicodec], - metadata: new Map().set("ping", lowPingBytes), - tags: new Map().set(Tags.BOOTSTRAP, {}) - } as Peer; - lowPingNonBootstrapPeer = { - id: lowPingNonBootstrapPeerId, - protocols: [waku.lightPush.protocol.multicodec], - metadata: new Map().set("ping", lowPingBytes), - tags: new Map().set(Tags.PEER_EXCHANGE, {}) - } as Peer; - midPingBootstrapPeer = { - id: midPingBootstrapPeerId, - protocols: [waku.lightPush.protocol.multicodec], - metadata: new Map().set("ping", midPingBytes), - tags: new Map().set(Tags.BOOTSTRAP, {}) - } as Peer; - midPingNonBootstrapPeer = { - id: midPingNonBootstrapPeerId, - protocols: [waku.lightPush.protocol.multicodec], - metadata: new Map().set("ping", midPingBytes), - tags: new Map().set(Tags.PEER_EXCHANGE, {}) - } as Peer; - highPingBootstrapPeer = { - id: highPingBootstrapPeerId, - protocols: [waku.lightPush.protocol.multicodec], - metadata: new Map().set("ping", highPingBytes), - tags: new Map().set(Tags.BOOTSTRAP, {}) - } as Peer; - highPingNonBootstrapPeer = { - id: highPingNonBootstrapPeerId, - protocols: [waku.lightPush.protocol.multicodec], - metadata: new Map().set("ping", highPingBytes), - tags: new Map().set(Tags.PEER_EXCHANGE, {}) - } as Peer; - differentCodecPeer = { - id: differentCodecPeerId, - protocols: ["different/1"], - metadata: new Map().set("ping", lowPingBytes), - tags: new Map().set(Tags.BOOTSTRAP, {}) - } as Peer; - anotherDifferentCodecPeer = { - id: anotherDifferentCodecPeerId, - protocols: ["different/2"], - metadata: new Map().set("ping", lowPingBytes), - tags: new Map().set(Tags.BOOTSTRAP, {}) - } as Peer; - - bootstrapPeers = [ - lowPingBootstrapPeer, - midPingBootstrapPeer, - highPingBootstrapPeer - ]; - - nonBootstrapPeers = [ - lowPingNonBootstrapPeer, - midPingNonBootstrapPeer, - highPingNonBootstrapPeer - ]; - - allPeers = [ - ...bootstrapPeers, - ...nonBootstrapPeers, - differentCodecPeer, - anotherDifferentCodecPeer - ]; - - allPeers.forEach((peer) => { - peer.metadata.set("shardInfo", encodeRelayShard(DefaultTestShardInfo)); - }); - - Sinon.stub(peerStore, "get").callsFake(async (peerId) => { - return allPeers.find((peer) => peer.id.equals(peerId))!; - }); - - Sinon.stub(peerStore, "forEach").callsFake(async (callback) => { - for (const peer of allPeers) { - callback(peer); - } - }); - - // assume all peers have an opened connection - Sinon.stub(connectionManager, "getConnections").callsFake(() => { - const connections: Connection[] = []; - for (const peer of allPeers) { - connections.push({ - status: "open", - remotePeer: peer.id, - streams: [{ protocol: waku.lightPush.protocol.multicodec }] - } as unknown as Connection); - } - return connections; - }); - }); - - afterEachCustom(this, async () => { - Sinon.restore(); - }); - - describe("getPeers with varying maxBootstrapPeers", function () { - const maxBootstrapPeersValues = [1, 2, 3, 4, 5, 6, 7]; - - maxBootstrapPeersValues.forEach((maxBootstrapPeers) => { - describe(`maxBootstrapPeers=${maxBootstrapPeers}`, function () { - it(`numPeers=1 -- returns one bootstrap peer `, async function () { - const result = (await (waku.lightPush.protocol as any).getPeers({ - numPeers: 1, - maxBootstrapPeers - })) as Peer[]; - - // Should only have 1 peer - expect(result).to.have.lengthOf(1); - - // The peer should be a bootstrap peer - expect(result[0].tags.has(Tags.BOOTSTRAP)).to.be.true; - - // Peer should be of the same protocol - expect( - result[0].protocols.includes(waku.lightPush.protocol.multicodec) - ).to.be.true; - - // Peer should have the lowest ping - expect(result[0].metadata.get("ping")).to.equal(lowPingBytes); - }); - - it(`numPeers=2 -- returns total 2 peers, with max ${maxBootstrapPeers} bootstrap peers`, async function () { - const result = (await (waku.lightPush.protocol as any).getPeers({ - numPeers: 2, - maxBootstrapPeers - })) as Peer[]; - - // Should only have 2 peers - expect(result).to.have.lengthOf(2); - - // Should only have ${maxBootstrapPeers} bootstrap peers - expect( - result.filter((peer: Peer) => peer.tags.has(Tags.BOOTSTRAP)).length - ).to.be.lessThanOrEqual(maxBootstrapPeers); - - // Should return peers with the same protocol - expect( - result.every((peer: Peer) => - peer.protocols.includes(waku.lightPush.protocol.multicodec) - ) - ).to.be.true; - - // All peers should be sorted by latency - // 0th index should be the lowest ping of all peers returned - expect(result[0].metadata.get("ping")).to.equal(lowPingBytes); - }); - - it(`numPeers=3 -- returns total 3 peers, with max ${maxBootstrapPeers} bootstrap peers`, async function () { - const result = (await (waku.lightPush.protocol as any).getPeers({ - numPeers: 3, - maxBootstrapPeers - })) as Peer[]; - - // Should only have 3 peers - expect(result).to.have.lengthOf(3); - - // Should only have ${maxBootstrapPeers} bootstrap peers - expect( - result.filter((peer: Peer) => peer.tags.has(Tags.BOOTSTRAP)).length - ).to.be.lessThanOrEqual(maxBootstrapPeers); - - // Should return peers with the same protocol - expect( - result.every((peer: Peer) => - peer.protocols.includes(waku.lightPush.protocol.multicodec) - ) - ).to.be.true; - - // All peers should be sorted by latency - // 0th index should be the lowest ping of all peers returned - expect(result[0].metadata.get("ping")).to.equal(lowPingBytes); - }); - - it(`numPeers=4 -- returns total 4 peers, with max ${maxBootstrapPeers} bootstrap peers`, async function () { - const result = (await (waku.lightPush.protocol as any).getPeers({ - numPeers: 4, - maxBootstrapPeers - })) as Peer[]; - - // Should only have 4 peers - expect(result).to.have.lengthOf(4); - - // Should only have ${maxBootstrapPeers} bootstrap peers - expect( - result.filter((peer: Peer) => peer.tags.has(Tags.BOOTSTRAP)).length - ).to.be.lessThanOrEqual(maxBootstrapPeers); - - // Should return peers with the same protocol - expect( - result.every((peer: Peer) => - peer.protocols.includes(waku.lightPush.protocol.multicodec) - ) - ).to.be.true; - - // All peers should be sorted by latency - // 0th index should be the lowest ping of all peers returned - expect(result[0].metadata.get("ping")).to.equal(lowPingBytes); - }); - - it(`numPeers=0 -- returns all peers including all non-bootstrap with maxBootstrapPeers: ${maxBootstrapPeers}`, async function () { - const result = (await (waku.lightPush.protocol as any).getPeers({ - numPeers: 0, - maxBootstrapPeers - })) as Peer[]; - - // Should have all non-bootstrap peers + ${maxBootstrapPeers} bootstrap peers - // Unless bootstrapPeers.length < maxBootstrapPeers - // Then it should be all non-bootstrap peers + bootstrapPeers.length - if (maxBootstrapPeers > bootstrapPeers.length) { - expect(result).to.have.lengthOf( - nonBootstrapPeers.length + bootstrapPeers.length - ); - } else { - expect(result).to.have.lengthOf( - nonBootstrapPeers.length + maxBootstrapPeers - ); - } - - // All peers should be bootstrap peers - expect( - result.filter((peer: Peer) => peer.tags.has(Tags.BOOTSTRAP)).length - ).to.be.lessThanOrEqual(maxBootstrapPeers); - - // Peers should be of the same protocol - expect( - result.every((peer: Peer) => - peer.protocols.includes(waku.lightPush.protocol.multicodec) - ) - ).to.be.true; - - // All peers returned should be sorted by latency - // 0th index should be the lowest ping of all peers returned - expect(result[0].metadata.get("ping")).to.equal(lowPingBytes); - }); - }); - }); - }); - - describe("getPeers property-based tests", function () { - it("should return the correct number of peers based on numPeers and maxBootstrapPeers", async function () { - await fc.assert( - fc.asyncProperty( - //max bootstrap peers - fc.integer({ min: 1, max: 100 }), - //numPeers - fc.integer({ min: 0, max: 100 }), - async (maxBootstrapPeers, numPeers) => { - const result = (await (waku.lightPush.protocol as any).getPeers({ - numPeers, - maxBootstrapPeers - })) as Peer[]; - - if (numPeers === 0) { - // Expect all peers when numPeers is 0 - expect(result.length).to.be.greaterThanOrEqual(1); - } else { - // Expect up to numPeers peers - expect(result.length).to.be.lessThanOrEqual(numPeers); - } - } - ), - { - verbose: true - } - ); - }); - }); -}); diff --git a/packages/utils/src/libp2p/index.ts b/packages/utils/src/libp2p/index.ts index 80feaec6b3..c24df61883 100644 --- a/packages/utils/src/libp2p/index.ts +++ b/packages/utils/src/libp2p/index.ts @@ -1,7 +1,5 @@ import type { Peer, PeerStore } from "@libp2p/interface"; -import { bytesToUtf8 } from "../bytes/index.js"; - /** * Returns a pseudo-random peer that supports the given protocol. * Useful for protocols such as store and light push @@ -13,42 +11,6 @@ export function selectRandomPeer(peers: Peer[]): Peer | undefined { return peers[index]; } -/** - * Function to sort peers by latency from lowest to highest - * @param peerStore - The Libp2p PeerStore - * @param peers - The list of peers to choose from - * @returns Sorted array of peers by latency - */ -export async function sortPeersByLatency( - peerStore: PeerStore, - peers: Peer[] -): Promise { - if (peers.length === 0) return []; - - const results = await Promise.all( - peers.map(async (peer) => { - try { - const pingBytes = (await peerStore.get(peer.id)).metadata.get("ping"); - if (!pingBytes) return { peer, ping: Infinity }; - - const ping = Number(bytesToUtf8(pingBytes)); - return { peer, ping }; - } catch (error) { - return { peer, ping: Infinity }; - } - }) - ); - - // filter out null values - const validResults = results.filter( - (result): result is { peer: Peer; ping: number } => result !== null - ); - - return validResults - .sort((a, b) => a.ping - b.ping) - .map((result) => result.peer); -} - /** * Returns the list of peers that supports the given protocol. */ From 9bdc2af13b16404698cc418c710d452b1ac2855a Mon Sep 17 00:00:00 2001 From: Sasha Date: Mon, 21 Oct 2024 01:34:33 +0200 Subject: [PATCH 06/12] remove allPeers and connectedPeers from BaseProtocolCore, update tests, add getPeers for IWaku --- packages/core/src/lib/base_protocol.ts | 20 ---------- packages/interfaces/src/protocols.ts | 2 - packages/interfaces/src/waku.ts | 7 +++- packages/sdk/src/waku/waku.ts | 6 ++- packages/tests/tests/metadata.spec.ts | 4 +- .../tests/wait_for_remote_peer.node.spec.ts | 37 +++++-------------- packages/utils/package.json | 4 -- packages/utils/src/libp2p/index.ts | 31 ---------------- 8 files changed, 24 insertions(+), 87 deletions(-) delete mode 100644 packages/utils/src/libp2p/index.ts diff --git a/packages/core/src/lib/base_protocol.ts b/packages/core/src/lib/base_protocol.ts index b8ed44e8d0..4143056599 100644 --- a/packages/core/src/lib/base_protocol.ts +++ b/packages/core/src/lib/base_protocol.ts @@ -5,7 +5,6 @@ import type { Libp2pComponents, PubsubTopic } from "@waku/interfaces"; -import { getPeersForProtocol } from "@waku/utils/libp2p"; import { StreamManager } from "./stream_manager/index.js"; @@ -42,23 +41,4 @@ export class BaseProtocol implements IBaseProtocolCore { protected async getStream(peer: Peer): Promise { return this.streamManager.getStream(peer); } - - /** - * Returns known peers from the address book (`libp2p.peerStore`) that support - * the class protocol. Waku may or may not be currently connected to these - * peers. - */ - public async allPeers(): Promise { - return getPeersForProtocol(this.components.peerStore, [this.multicodec]); - } - - public async connectedPeers(): Promise { - const peers = await this.allPeers(); - return peers.filter((peer) => { - const connections = this.components.connectionManager.getConnections( - peer.id - ); - return connections.length > 0; - }); - } } diff --git a/packages/interfaces/src/protocols.ts b/packages/interfaces/src/protocols.ts index e18ca6592a..664ed49f3c 100644 --- a/packages/interfaces/src/protocols.ts +++ b/packages/interfaces/src/protocols.ts @@ -17,8 +17,6 @@ export enum Protocols { export type IBaseProtocolCore = { multicodec: string; - allPeers: () => Promise; - connectedPeers: () => Promise; addLibp2pEventListener: Libp2p["addEventListener"]; removeLibp2pEventListener: Libp2p["removeEventListener"]; }; diff --git a/packages/interfaces/src/waku.ts b/packages/interfaces/src/waku.ts index 4f3edf4f86..733fb5093e 100644 --- a/packages/interfaces/src/waku.ts +++ b/packages/interfaces/src/waku.ts @@ -1,4 +1,4 @@ -import type { PeerId, Stream } from "@libp2p/interface"; +import type { Peer, PeerId, Stream } from "@libp2p/interface"; import type { MultiaddrInput } from "@multiformats/multiaddr"; import { IConnectionManager } from "./connection_manager.js"; @@ -121,6 +121,11 @@ export interface IWaku { * @returns {boolean} `true` if the node has working connection and `false` otherwise */ isConnected(): boolean; + + /** + * @returns {Peer[]} an array of all connected peers + */ + getPeers(): Promise; } export interface LightNode extends IWaku { diff --git a/packages/sdk/src/waku/waku.ts b/packages/sdk/src/waku/waku.ts index 0f492857b0..76bbad601c 100644 --- a/packages/sdk/src/waku/waku.ts +++ b/packages/sdk/src/waku/waku.ts @@ -1,5 +1,5 @@ import type { Stream } from "@libp2p/interface"; -import { isPeerId, PeerId } from "@libp2p/interface"; +import { isPeerId, Peer, PeerId } from "@libp2p/interface"; import { multiaddr, Multiaddr, MultiaddrInput } from "@multiformats/multiaddr"; import { ConnectionManager, getHealthManager } from "@waku/core"; import type { @@ -186,6 +186,10 @@ export class WakuNode implements IWaku { await this.libp2p.stop(); } + public async getPeers(): Promise { + return this.connectionManager.getConnectedPeers(); + } + public async waitForPeers( protocols?: Protocols[], timeoutMs?: number diff --git a/packages/tests/tests/metadata.spec.ts b/packages/tests/tests/metadata.spec.ts index 98099873e8..80625e2bb3 100644 --- a/packages/tests/tests/metadata.spec.ts +++ b/packages/tests/tests/metadata.spec.ts @@ -253,7 +253,9 @@ describe("Metadata Protocol", function () { waku = await createLightNode({ networkConfig: shardInfo, - pingKeepAlive: 1 + connectionManager: { + pingKeepAlive: 1 + } }); await waku.start(); await waku.libp2p.dialProtocol(nwaku1Ma, MetadataCodec); diff --git a/packages/tests/tests/wait_for_remote_peer.node.spec.ts b/packages/tests/tests/wait_for_remote_peer.node.spec.ts index 1b3e039c45..37b5d6e632 100644 --- a/packages/tests/tests/wait_for_remote_peer.node.spec.ts +++ b/packages/tests/tests/wait_for_remote_peer.node.spec.ts @@ -115,9 +115,7 @@ describe("Wait for remote peer", function () { await delay(1000); await waku2.waitForPeers([Protocols.Store]); - const peers = (await waku2.store.protocol.connectedPeers()).map((peer) => - peer.id.toString() - ); + const peers = (await waku2.getPeers()).map((peer) => peer.id.toString()); const nimPeerId = multiAddrWithId.getPeerId(); expect(nimPeerId).to.not.be.undefined; @@ -145,9 +143,7 @@ describe("Wait for remote peer", function () { await waku2.dial(multiAddrWithId); await waitPromise; - const peers = (await waku2.store.protocol.connectedPeers()).map((peer) => - peer.id.toString() - ); + const peers = (await waku2.getPeers()).map((peer) => peer.id.toString()); const nimPeerId = multiAddrWithId.getPeerId(); @@ -174,9 +170,7 @@ describe("Wait for remote peer", function () { await waku2.dial(multiAddrWithId); await waku2.waitForPeers([Protocols.LightPush]); - const peers = (await waku2.lightPush.protocol.connectedPeers()).map( - (peer) => peer.id.toString() - ); + const peers = (await waku2.getPeers()).map((peer) => peer.id.toString()); const nimPeerId = multiAddrWithId.getPeerId(); @@ -203,9 +197,7 @@ describe("Wait for remote peer", function () { await waku2.dial(multiAddrWithId); await waku2.waitForPeers([Protocols.Filter]); - const peers = (await waku2.filter.protocol.connectedPeers()).map((peer) => - peer.id.toString() - ); + const peers = (await waku2.getPeers()).map((peer) => peer.id.toString()); const nimPeerId = multiAddrWithId.getPeerId(); @@ -213,14 +205,15 @@ describe("Wait for remote peer", function () { expect(peers.includes(nimPeerId as string)).to.be.true; }); + // TODO: re-enable store once https://github.com/waku-org/js-waku/issues/2162 is fixed it("Light Node - default protocols", async function () { this.timeout(20_000); nwaku = new ServiceNode(makeLogFileName(this)); await nwaku.start({ filter: true, lightpush: true, - relay: false, - store: true + relay: false + // store: true }); const multiAddrWithId = await nwaku.getMultiaddrWithId(); @@ -232,26 +225,16 @@ describe("Wait for remote peer", function () { await waku2.dial(multiAddrWithId); await waku2.waitForPeers([ Protocols.Filter, - Protocols.Store, + // Protocols.Store, Protocols.LightPush ]); - const filterPeers = (await waku2.filter.protocol.connectedPeers()).map( - (peer) => peer.id.toString() - ); - const storePeers = (await waku2.store.protocol.connectedPeers()).map( - (peer) => peer.id.toString() - ); - const lightPushPeers = ( - await waku2.lightPush.protocol.connectedPeers() - ).map((peer) => peer.id.toString()); + const peers = (await waku2.getPeers()).map((peer) => peer.id.toString()); const nimPeerId = multiAddrWithId.getPeerId(); expect(nimPeerId).to.not.be.undefined; - expect(filterPeers.includes(nimPeerId as string)).to.be.true; - expect(storePeers.includes(nimPeerId as string)).to.be.true; - expect(lightPushPeers.includes(nimPeerId as string)).to.be.true; + expect(peers.includes(nimPeerId as string)).to.be.true; }); it("Privacy Node - default protocol", async function () { diff --git a/packages/utils/package.json b/packages/utils/package.json index 99d132eb1f..8538b08a8f 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -9,10 +9,6 @@ "types": "./dist/index.d.ts", "import": "./dist/index.js" }, - "./libp2p": { - "types": "./dist/libp2p/index.d.ts", - "import": "./dist/libp2p/index.js" - }, "./bytes": { "types": "./dist/bytes/index.d.ts", "import": "./dist/bytes/index.js" diff --git a/packages/utils/src/libp2p/index.ts b/packages/utils/src/libp2p/index.ts deleted file mode 100644 index c24df61883..0000000000 --- a/packages/utils/src/libp2p/index.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { Peer, PeerStore } from "@libp2p/interface"; - -/** - * Returns a pseudo-random peer that supports the given protocol. - * Useful for protocols such as store and light push - */ -export function selectRandomPeer(peers: Peer[]): Peer | undefined { - if (peers.length === 0) return; - - const index = Math.round(Math.random() * (peers.length - 1)); - return peers[index]; -} - -/** - * Returns the list of peers that supports the given protocol. - */ -export async function getPeersForProtocol( - peerStore: PeerStore, - protocols: string[] -): Promise { - const peers: Peer[] = []; - await peerStore.forEach((peer) => { - for (let i = 0; i < protocols.length; i++) { - if (peer.protocols.includes(protocols[i])) { - peers.push(peer); - break; - } - } - }); - return peers; -} From 2edd8564345d28caac85d534f3b1fac3b597f2ea Mon Sep 17 00:00:00 2001 From: Sasha Date: Tue, 22 Oct 2024 15:21:50 +0200 Subject: [PATCH 07/12] use only one peerManager from Waku object --- packages/sdk/src/protocols/base_protocol.ts | 6 +----- packages/sdk/src/protocols/filter/index.ts | 9 ++++++--- packages/sdk/src/protocols/store/index.ts | 22 +++++++++++---------- packages/sdk/src/waku/waku.ts | 8 +++++++- 4 files changed, 26 insertions(+), 19 deletions(-) diff --git a/packages/sdk/src/protocols/base_protocol.ts b/packages/sdk/src/protocols/base_protocol.ts index 3a7abc1b36..566dda9155 100644 --- a/packages/sdk/src/protocols/base_protocol.ts +++ b/packages/sdk/src/protocols/base_protocol.ts @@ -1,5 +1,4 @@ import type { Peer, PeerId } from "@libp2p/interface"; -import { ConnectionManager } from "@waku/core"; import { BaseProtocol } from "@waku/core/lib/base_protocol"; import { IBaseProtocolSDK, ProtocolUseOptions } from "@waku/interfaces"; import { Logger } from "@waku/utils"; @@ -15,7 +14,6 @@ export const DEFAULT_NUM_PEERS_TO_USE = 2; const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000; export class BaseProtocolSDK implements IBaseProtocolSDK { - private peerManager: PeerManager; public readonly numPeersToUse: number; private maintainPeersIntervalId: ReturnType< typeof window.setInterval @@ -24,7 +22,7 @@ export class BaseProtocolSDK implements IBaseProtocolSDK { public constructor( protected core: BaseProtocol, - protected connectionManager: ConnectionManager, + protected peerManager: PeerManager, options: Options ) { this.log = new Logger(`sdk:${core.multicodec}`); @@ -33,8 +31,6 @@ export class BaseProtocolSDK implements IBaseProtocolSDK { const maintainPeersInterval = options?.maintainPeersInterval ?? DEFAULT_MAINTAIN_PEERS_INTERVAL; - this.peerManager = new PeerManager(connectionManager); - this.log.info( `Initializing BaseProtocolSDK with numPeersToUse: ${this.numPeersToUse}, maintainPeersInterval: ${maintainPeersInterval}ms` ); diff --git a/packages/sdk/src/protocols/filter/index.ts b/packages/sdk/src/protocols/filter/index.ts index d5509c2337..1db0ed1d37 100644 --- a/packages/sdk/src/protocols/filter/index.ts +++ b/packages/sdk/src/protocols/filter/index.ts @@ -26,6 +26,7 @@ import { } from "@waku/utils"; import { BaseProtocolSDK } from "../base_protocol.js"; +import { PeerManager } from "../peer_manager.js"; import { DEFAULT_SUBSCRIBE_OPTIONS } from "./constants.js"; import { SubscriptionManager } from "./subscription_manager.js"; @@ -38,8 +39,9 @@ class Filter extends BaseProtocolSDK implements IFilter { private activeSubscriptions = new Map(); public constructor( - connectionManager: ConnectionManager, + private connectionManager: ConnectionManager, private libp2p: Libp2p, + peerManager: PeerManager, private lightPush?: ILightPush, options?: ProtocolCreateOptions ) { @@ -59,7 +61,7 @@ class Filter extends BaseProtocolSDK implements IFilter { connectionManager.pubsubTopics, libp2p ), - connectionManager, + peerManager, { numPeersToUse: options?.numPeersToUse } ); @@ -304,9 +306,10 @@ class Filter extends BaseProtocolSDK implements IFilter { export function wakuFilter( connectionManager: ConnectionManager, + peerManager: PeerManager, lightPush?: ILightPush, init?: ProtocolCreateOptions ): (libp2p: Libp2p) => IFilter { return (libp2p: Libp2p) => - new Filter(connectionManager, libp2p, lightPush, init); + new Filter(connectionManager, libp2p, peerManager, lightPush, init); } diff --git a/packages/sdk/src/protocols/store/index.ts b/packages/sdk/src/protocols/store/index.ts index efd58033f8..36249a0f2f 100644 --- a/packages/sdk/src/protocols/store/index.ts +++ b/packages/sdk/src/protocols/store/index.ts @@ -11,6 +11,7 @@ import { messageHash } from "@waku/message-hash"; import { ensurePubsubTopicIsConfigured, isDefined, Logger } from "@waku/utils"; import { BaseProtocolSDK } from "../base_protocol.js"; +import { PeerManager } from "../peer_manager.js"; const DEFAULT_NUM_PEERS = 1; @@ -23,14 +24,14 @@ const log = new Logger("waku:store:sdk"); export class Store extends BaseProtocolSDK implements IStore { public readonly protocol: StoreCore; - public constructor(connectionManager: ConnectionManager, libp2p: Libp2p) { - super( - new StoreCore(connectionManager.pubsubTopics, libp2p), - connectionManager, - { - numPeersToUse: DEFAULT_NUM_PEERS - } - ); + public constructor( + private connectionManager: ConnectionManager, + libp2p: Libp2p, + peerManager: PeerManager + ) { + super(new StoreCore(connectionManager.pubsubTopics, libp2p), peerManager, { + numPeersToUse: DEFAULT_NUM_PEERS + }); this.protocol = this.core as StoreCore; } @@ -236,9 +237,10 @@ export class Store extends BaseProtocolSDK implements IStore { * @returns A function that takes a Libp2p instance and returns a StoreSDK instance. */ export function wakuStore( - connectionManager: ConnectionManager + connectionManager: ConnectionManager, + peerManager: PeerManager ): (libp2p: Libp2p) => IStore { return (libp2p: Libp2p) => { - return new Store(connectionManager, libp2p); + return new Store(connectionManager, libp2p, peerManager); }; } diff --git a/packages/sdk/src/waku/waku.ts b/packages/sdk/src/waku/waku.ts index 76bbad601c..90572896d9 100644 --- a/packages/sdk/src/waku/waku.ts +++ b/packages/sdk/src/waku/waku.ts @@ -18,6 +18,7 @@ import { Logger } from "@waku/utils"; import { wakuFilter } from "../protocols/filter/index.js"; import { wakuLightPush } from "../protocols/light_push/index.js"; +import { PeerManager } from "../protocols/peer_manager.js"; import { wakuStore } from "../protocols/store/index.js"; import { ReliabilityMonitorManager } from "../reliability_monitor/index.js"; @@ -54,6 +55,8 @@ export class WakuNode implements IWaku { public connectionManager: ConnectionManager; public readonly health: IHealthManager; + private readonly peerManager: PeerManager; + public constructor( public readonly pubsubTopics: PubsubTopic[], options: CreateWakuNodeOptions, @@ -80,10 +83,12 @@ export class WakuNode implements IWaku { config: options?.connectionManager }); + this.peerManager = new PeerManager(this.connectionManager); + this.health = getHealthManager(); if (protocolsEnabled.store) { - const store = wakuStore(this.connectionManager); + const store = wakuStore(this.connectionManager, this.peerManager); this.store = store(libp2p); } @@ -95,6 +100,7 @@ export class WakuNode implements IWaku { if (protocolsEnabled.filter) { const filter = wakuFilter( this.connectionManager, + this.peerManager, this.lightPush, options ); From 7ae3b91b98471e35dfb2190618f67fd242910a78 Mon Sep 17 00:00:00 2001 From: Sasha Date: Tue, 22 Oct 2024 16:02:40 +0200 Subject: [PATCH 08/12] remove IBaseProtocolSDK and merge with PeerManager --- packages/interfaces/src/filter.ts | 18 +- packages/interfaces/src/protocols.ts | 7 - packages/interfaces/src/store.ts | 4 +- packages/sdk/src/protocols/base_protocol.ts | 187 ------------------ packages/sdk/src/protocols/filter/index.ts | 58 +++--- .../protocols/light_push/light_push.spec.ts | 3 +- .../src/protocols/light_push/light_push.ts | 33 +--- packages/sdk/src/protocols/peer_manager.ts | 178 ++++++++++++++++- packages/sdk/src/protocols/store/index.ts | 18 +- packages/sdk/src/waku/waku.ts | 12 +- 10 files changed, 234 insertions(+), 284 deletions(-) delete mode 100644 packages/sdk/src/protocols/base_protocol.ts diff --git a/packages/interfaces/src/filter.ts b/packages/interfaces/src/filter.ts index bbe6bb351b..373aac5121 100644 --- a/packages/interfaces/src/filter.ts +++ b/packages/interfaces/src/filter.ts @@ -5,7 +5,6 @@ import type { ContentTopic, ThisOrThat } from "./misc.js"; import type { Callback, IBaseProtocolCore, - IBaseProtocolSDK, ProtocolError, ProtocolUseOptions, SDKProtocolResult @@ -37,15 +36,14 @@ export interface ISubscription { unsubscribeAll(): Promise; } -export type IFilter = IReceiver & - IBaseProtocolSDK & { protocol: IBaseProtocolCore } & { - subscribe( - decoders: IDecoder | IDecoder[], - callback: Callback, - protocolUseOptions?: ProtocolUseOptions, - subscribeOptions?: SubscribeOptions - ): Promise; - }; +export type IFilter = IReceiver & { protocol: IBaseProtocolCore } & { + subscribe( + decoders: IDecoder | IDecoder[], + callback: Callback, + protocolUseOptions?: ProtocolUseOptions, + subscribeOptions?: SubscribeOptions + ): Promise; +}; export type SubscribeResult = SubscriptionSuccess | SubscriptionError; diff --git a/packages/interfaces/src/protocols.ts b/packages/interfaces/src/protocols.ts index 664ed49f3c..42e4708911 100644 --- a/packages/interfaces/src/protocols.ts +++ b/packages/interfaces/src/protocols.ts @@ -1,6 +1,5 @@ import type { Libp2p } from "@libp2p/interface"; import type { PeerId } from "@libp2p/interface"; -import type { Peer } from "@libp2p/interface"; import type { ConnectionManagerOptions } from "./connection_manager.js"; import type { CreateLibp2pOptions } from "./libp2p.js"; @@ -21,12 +20,6 @@ export type IBaseProtocolCore = { removeLibp2pEventListener: Libp2p["removeEventListener"]; }; -export type IBaseProtocolSDK = { - readonly connectedPeers: Peer[]; - renewPeer: (peerToDisconnect: PeerId) => Promise; - readonly numPeersToUse: number; -}; - export type NetworkConfig = StaticSharding | AutoSharding; //TODO: merge this with ProtocolCreateOptions or establish distinction: https://github.com/waku-org/js-waku/issues/2048 diff --git a/packages/interfaces/src/store.ts b/packages/interfaces/src/store.ts index 44560db62f..a613ef73ac 100644 --- a/packages/interfaces/src/store.ts +++ b/packages/interfaces/src/store.ts @@ -1,5 +1,5 @@ import type { IDecodedMessage, IDecoder } from "./message.js"; -import type { IBaseProtocolCore, IBaseProtocolSDK } from "./protocols.js"; +import type { IBaseProtocolCore } from "./protocols.js"; export type StoreCursor = Uint8Array; @@ -78,7 +78,7 @@ export type QueryRequestParams = { export type IStoreCore = IBaseProtocolCore; -export type IStore = IBaseProtocolSDK & { +export type IStore = { protocol: IBaseProtocolCore; createCursor(message: IDecodedMessage): StoreCursor; queryGenerator: ( diff --git a/packages/sdk/src/protocols/base_protocol.ts b/packages/sdk/src/protocols/base_protocol.ts deleted file mode 100644 index 566dda9155..0000000000 --- a/packages/sdk/src/protocols/base_protocol.ts +++ /dev/null @@ -1,187 +0,0 @@ -import type { Peer, PeerId } from "@libp2p/interface"; -import { BaseProtocol } from "@waku/core/lib/base_protocol"; -import { IBaseProtocolSDK, ProtocolUseOptions } from "@waku/interfaces"; -import { Logger } from "@waku/utils"; - -import { PeerManager } from "./peer_manager.js"; - -interface Options { - numPeersToUse?: number; - maintainPeersInterval?: number; -} - -export const DEFAULT_NUM_PEERS_TO_USE = 2; -const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000; - -export class BaseProtocolSDK implements IBaseProtocolSDK { - public readonly numPeersToUse: number; - private maintainPeersIntervalId: ReturnType< - typeof window.setInterval - > | null = null; - private log: Logger; - - public constructor( - protected core: BaseProtocol, - protected peerManager: PeerManager, - options: Options - ) { - this.log = new Logger(`sdk:${core.multicodec}`); - - this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE; - const maintainPeersInterval = - options?.maintainPeersInterval ?? DEFAULT_MAINTAIN_PEERS_INTERVAL; - - this.log.info( - `Initializing BaseProtocolSDK with numPeersToUse: ${this.numPeersToUse}, maintainPeersInterval: ${maintainPeersInterval}ms` - ); - void this.startMaintainPeersInterval(maintainPeersInterval); - } - - public get connectedPeers(): Peer[] { - return this.peerManager.getPeers().slice(0, this.numPeersToUse); - } - - /** - * Disconnects from a peer and tries to find a new one to replace it. - * @param peerToDisconnect The peer to disconnect from. - * @returns The new peer that was found and connected to. - */ - public async renewPeer(peerToDisconnect: PeerId): Promise { - this.log.info(`Attempting to renew peer ${peerToDisconnect}`); - - const newPeer = await this.peerManager.findPeers(1); - if (newPeer.length === 0) { - this.log.error( - "Failed to find a new peer to replace the disconnected one" - ); - return undefined; - } - - await this.peerManager.removePeer(peerToDisconnect); - await this.peerManager.addPeer(newPeer[0]); - - this.log.info(`Successfully renewed peer. New peer: ${newPeer[0].id}`); - - return newPeer[0]; - } - - /** - * Stops the maintain peers interval. - */ - public stopMaintainPeersInterval(): void { - if (this.maintainPeersIntervalId) { - clearInterval(this.maintainPeersIntervalId); - this.maintainPeersIntervalId = null; - this.log.info("Maintain peers interval stopped"); - } else { - this.log.info("Maintain peers interval was not running"); - } - } - - /** - * Checks if there are sufficient peers to send a message to. - * If `forceUseAllPeers` is `false` (default), returns `true` if there are any connected peers. - * If `forceUseAllPeers` is `true`, attempts to connect to `numPeersToUse` peers. - * @param options Optional options object - * @param options.forceUseAllPeers Optional flag to force connecting to `numPeersToUse` peers (default: false) - * @param options.maxAttempts Optional maximum number of attempts to reach the required number of peers (default: 3) - * @returns `true` if the required number of peers are connected, `false` otherwise - */ - protected async hasPeers( - options: Partial = {} - ): Promise { - const { forceUseAllPeers = false, maxAttempts = 3 } = options; - - this.log.info( - `Checking for peers. forceUseAllPeers: ${forceUseAllPeers}, maxAttempts: ${maxAttempts}` - ); - - for (let attempts = 0; attempts < maxAttempts; attempts++) { - this.log.info( - `Attempt ${attempts + 1}/${maxAttempts} to reach required number of peers` - ); - await this.maintainPeers(); - - if (!forceUseAllPeers && this.connectedPeers.length > 0) { - this.log.info( - `At least one peer connected (${this.connectedPeers.length}), not forcing use of all peers` - ); - return true; - } - - if (this.connectedPeers.length >= this.numPeersToUse) { - this.log.info( - `Required number of peers (${this.numPeersToUse}) reached` - ); - return true; - } - - this.log.warn( - `Found only ${this.connectedPeers.length}/${this.numPeersToUse} required peers. Retrying...` - ); - } - - this.log.error( - `Failed to find required number of peers (${this.numPeersToUse}) after ${maxAttempts} attempts` - ); - return false; - } - - /** - * Starts an interval to maintain the peers list to `numPeersToUse`. - * @param interval The interval in milliseconds to maintain the peers. - */ - private async startMaintainPeersInterval(interval: number): Promise { - this.log.info( - `Starting maintain peers interval with ${interval}ms interval` - ); - try { - this.maintainPeersIntervalId = setInterval(() => { - this.log.info("Running scheduled peer maintenance"); - this.maintainPeers().catch((error) => { - this.log.error("Error during scheduled peer maintenance:", error); - }); - }, interval); - this.log.info("Maintain peers interval started successfully"); - } catch (error) { - this.log.error("Error starting maintain peers interval:", error); - throw error; - } - } - - /** - * Maintains the peers list to `numPeersToUse`. - */ - private async maintainPeers(): Promise { - try { - const currentPeerCount = await this.peerManager.getPeerCount(); - const numPeersToAdd = this.numPeersToUse - currentPeerCount; - - this.log.info( - `Current peer count: ${currentPeerCount}, target: ${this.numPeersToUse}` - ); - - if (numPeersToAdd === 0) { - this.log.info("Peer count is at target, no maintenance required"); - return; - } - - if (numPeersToAdd > 0) { - this.log.info(`Attempting to add ${numPeersToAdd} peer(s)`); - await this.peerManager.findAndAddPeers(numPeersToAdd); - } else { - this.log.info( - `Attempting to remove ${Math.abs(numPeersToAdd)} excess peer(s)` - ); - await this.peerManager.removeExcessPeers(Math.abs(numPeersToAdd)); - } - - const finalPeerCount = await this.peerManager.getPeerCount(); - this.log.info( - `Peer maintenance completed. Initial count: ${currentPeerCount}, Final count: ${finalPeerCount}` - ); - } catch (error) { - this.log.error("Error during peer maintenance", { error }); - } - } -} diff --git a/packages/sdk/src/protocols/filter/index.ts b/packages/sdk/src/protocols/filter/index.ts index 1db0ed1d37..d0cfa50a44 100644 --- a/packages/sdk/src/protocols/filter/index.ts +++ b/packages/sdk/src/protocols/filter/index.ts @@ -9,7 +9,6 @@ import { type ILightPush, type Libp2p, NetworkConfig, - type ProtocolCreateOptions, ProtocolError, type ProtocolUseOptions, type PubsubTopic, @@ -25,7 +24,6 @@ import { toAsyncIterator } from "@waku/utils"; -import { BaseProtocolSDK } from "../base_protocol.js"; import { PeerManager } from "../peer_manager.js"; import { DEFAULT_SUBSCRIBE_OPTIONS } from "./constants.js"; @@ -33,7 +31,7 @@ import { SubscriptionManager } from "./subscription_manager.js"; const log = new Logger("sdk:filter"); -class Filter extends BaseProtocolSDK implements IFilter { +class Filter implements IFilter { public readonly protocol: FilterCore; private activeSubscriptions = new Map(); @@ -41,32 +39,25 @@ class Filter extends BaseProtocolSDK implements IFilter { public constructor( private connectionManager: ConnectionManager, private libp2p: Libp2p, - peerManager: PeerManager, - private lightPush?: ILightPush, - options?: ProtocolCreateOptions + private peerManager: PeerManager, + private lightPush?: ILightPush ) { - super( - new FilterCore( - async (pubsubTopic, wakuMessage, peerIdStr) => { - const subscription = this.getActiveSubscription(pubsubTopic); - if (!subscription) { - log.error( - `No subscription locally registered for topic ${pubsubTopic}` - ); - return; - } - await subscription.processIncomingMessage(wakuMessage, peerIdStr); - }, - - connectionManager.pubsubTopics, - libp2p - ), - peerManager, - { numPeersToUse: options?.numPeersToUse } + this.protocol = new FilterCore( + async (pubsubTopic, wakuMessage, peerIdStr) => { + const subscription = this.getActiveSubscription(pubsubTopic); + if (!subscription) { + log.error( + `No subscription locally registered for topic ${pubsubTopic}` + ); + return; + } + await subscription.processIncomingMessage(wakuMessage, peerIdStr); + }, + + connectionManager.pubsubTopics, + libp2p ); - this.protocol = this.core as FilterCore; - this.activeSubscriptions = new Map(); } @@ -177,7 +168,7 @@ class Filter extends BaseProtocolSDK implements IFilter { ensurePubsubTopicIsConfigured(pubsubTopic, this.protocol.pubsubTopics); - const hasPeers = await this.hasPeers(options); + const hasPeers = await this.peerManager.hasPeersWithMaintain(options); if (!hasPeers) { return { error: ProtocolError.NO_PEER_AVAILABLE, @@ -186,8 +177,8 @@ class Filter extends BaseProtocolSDK implements IFilter { } log.info( - `Creating filter subscription with ${this.connectedPeers.length} peers: `, - this.connectedPeers.map((peer) => peer.id.toString()) + `Creating filter subscription with ${this.peerManager.connectedPeers.length} peers: `, + this.peerManager.connectedPeers.map((peer) => peer.id.toString()) ); const subscription = @@ -198,8 +189,8 @@ class Filter extends BaseProtocolSDK implements IFilter { pubsubTopic, this.protocol, this.connectionManager, - () => this.connectedPeers, - this.renewPeer.bind(this), + () => this.peerManager.connectedPeers, + this.peerManager.renewPeer.bind(this), this.libp2p, this.lightPush ) @@ -307,9 +298,8 @@ class Filter extends BaseProtocolSDK implements IFilter { export function wakuFilter( connectionManager: ConnectionManager, peerManager: PeerManager, - lightPush?: ILightPush, - init?: ProtocolCreateOptions + lightPush?: ILightPush ): (libp2p: Libp2p) => IFilter { return (libp2p: Libp2p) => - new Filter(connectionManager, libp2p, peerManager, lightPush, init); + new Filter(connectionManager, libp2p, peerManager, lightPush); } diff --git a/packages/sdk/src/protocols/light_push/light_push.spec.ts b/packages/sdk/src/protocols/light_push/light_push.spec.ts index afc2da78e2..1e0a24293c 100644 --- a/packages/sdk/src/protocols/light_push/light_push.spec.ts +++ b/packages/sdk/src/protocols/light_push/light_push.spec.ts @@ -157,8 +157,7 @@ function mockLightPush(options: MockLightPushOptions): LightPush { { configuredPubsubTopics: options.pubsubTopics || [PUBSUB_TOPIC] } as ConnectionManager, - options.libp2p, - { numPeersToUse: options.numPeersToUse } + options.libp2p ); } diff --git a/packages/sdk/src/protocols/light_push/light_push.ts b/packages/sdk/src/protocols/light_push/light_push.ts index 478e683b7d..fb1ca55d22 100644 --- a/packages/sdk/src/protocols/light_push/light_push.ts +++ b/packages/sdk/src/protocols/light_push/light_push.ts @@ -1,10 +1,5 @@ import type { Peer, PeerId } from "@libp2p/interface"; -import { - ConnectionManager, - getHealthManager, - LightPushCodec, - LightPushCore -} from "@waku/core"; +import { ConnectionManager, getHealthManager, LightPushCore } from "@waku/core"; import { type CoreProtocolResult, Failure, @@ -13,13 +8,12 @@ import { type IMessage, type ISenderOptions, type Libp2p, - type ProtocolCreateOptions, ProtocolError, SDKProtocolResult } from "@waku/interfaces"; import { ensurePubsubTopicIsConfigured, Logger } from "@waku/utils"; -import { DEFAULT_NUM_PEERS_TO_USE } from "../base_protocol.js"; +import { PeerManager } from "../peer_manager.js"; const log = new Logger("sdk:light-push"); @@ -32,15 +26,13 @@ const DEFAULT_SEND_OPTIONS: ISenderOptions = { type RetryCallback = (peer: Peer) => Promise; export class LightPush implements ILightPush { - private numPeersToUse: number = DEFAULT_NUM_PEERS_TO_USE; public readonly protocol: LightPushCore; public constructor( - private connectionManager: ConnectionManager, - libp2p: Libp2p, - options?: ProtocolCreateOptions + connectionManager: ConnectionManager, + private peerManager: PeerManager, + libp2p: Libp2p ) { - this.numPeersToUse = options?.numPeersToUse ?? DEFAULT_NUM_PEERS_TO_USE; this.protocol = new LightPushCore(connectionManager.pubsubTopics, libp2p); } @@ -67,7 +59,7 @@ export class LightPush implements ILightPush { }; } - const peers = await this.getConnectedPeers(); + const peers = this.peerManager.getPeers(); if (peers.length === 0) { return { successes, @@ -125,7 +117,7 @@ export class LightPush implements ILightPush { maxAttempts?: number ): Promise { maxAttempts = maxAttempts || DEFAULT_MAX_ATTEMPTS; - const connectedPeers = await this.getConnectedPeers(); + const connectedPeers = this.peerManager.getPeers(); if (connectedPeers.length === 0) { log.warn("Cannot retry with no connected peers."); @@ -145,17 +137,12 @@ export class LightPush implements ILightPush { ); } } - - private async getConnectedPeers(): Promise { - const peers = - await this.connectionManager.getConnectedPeers(LightPushCodec); - return peers.slice(0, this.numPeersToUse); - } } export function wakuLightPush( connectionManager: ConnectionManager, - init: Partial = {} + peerManager: PeerManager ): (libp2p: Libp2p) => ILightPush { - return (libp2p: Libp2p) => new LightPush(connectionManager, libp2p, init); + return (libp2p: Libp2p) => + new LightPush(connectionManager, peerManager, libp2p); } diff --git a/packages/sdk/src/protocols/peer_manager.ts b/packages/sdk/src/protocols/peer_manager.ts index d8bf25f0bc..4d9b98a4d5 100644 --- a/packages/sdk/src/protocols/peer_manager.ts +++ b/packages/sdk/src/protocols/peer_manager.ts @@ -1,10 +1,24 @@ import { Peer, PeerId } from "@libp2p/interface"; import { ConnectionManager } from "@waku/core"; +import { ProtocolUseOptions } from "@waku/interfaces"; import { Logger } from "@waku/utils"; import { Mutex } from "async-mutex"; const log = new Logger("peer-manager"); +const DEFAULT_NUM_PEERS_TO_USE = 2; +const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000; + +type PeerManagerConfig = { + numPeersToUse?: number; + maintainPeersIntervalMs?: number; +}; + +type PeerManagerParams = { + config?: PeerManagerConfig; + connectionManager: ConnectionManager; +}; + export class PeerManager { private peers: Map = new Map(); @@ -12,16 +26,176 @@ export class PeerManager { private writeMutex = new Mutex(); private writeLockHolder: string | null = null; - public constructor(private readonly connectionManager: ConnectionManager) {} + private readonly numPeersToUse: number; + private readonly maintainPeersIntervalMs: number; + private readonly connectionManager: ConnectionManager; + + private maintainPeersIntervalId: ReturnType< + typeof window.setInterval + > | null = null; + + public constructor(params: PeerManagerParams) { + this.numPeersToUse = + params?.config?.numPeersToUse || DEFAULT_NUM_PEERS_TO_USE; + this.maintainPeersIntervalMs = + params?.config?.maintainPeersIntervalMs || + DEFAULT_MAINTAIN_PEERS_INTERVAL; + + this.connectionManager = params.connectionManager; + + void this.startMaintainPeersInterval(this.maintainPeersIntervalMs); + } + + /** + * Disconnects from a peer and tries to find a new one to replace it. + * @param peerToDisconnect The peer to disconnect from. + * @returns The new peer that was found and connected to. + */ + public async renewPeer(peerToDisconnect: PeerId): Promise { + log.info(`Attempting to renew peer ${peerToDisconnect}`); + + const newPeer = await this.findPeers(1); + if (newPeer.length === 0) { + log.error("Failed to find a new peer to replace the disconnected one"); + return undefined; + } + + await this.removePeer(peerToDisconnect); + await this.addPeer(newPeer[0]); + + log.info(`Successfully renewed peer. New peer: ${newPeer[0].id}`); + + return newPeer[0]; + } + + /** + * Stops the maintain peers interval. + */ + public stopMaintainPeersInterval(): void { + if (this.maintainPeersIntervalId) { + clearInterval(this.maintainPeersIntervalId); + this.maintainPeersIntervalId = null; + log.info("Maintain peers interval stopped"); + } else { + log.info("Maintain peers interval was not running"); + } + } + + /** + * Checks if there are sufficient peers to send a message to. + * If `forceUseAllPeers` is `false` (default), returns `true` if there are any connected peers. + * If `forceUseAllPeers` is `true`, attempts to connect to `numPeersToUse` peers. + * @param options Optional options object + * @param options.forceUseAllPeers Optional flag to force connecting to `numPeersToUse` peers (default: false) + * @param options.maxAttempts Optional maximum number of attempts to reach the required number of peers (default: 3) + * @returns `true` if the required number of peers are connected, `false` otherwise + */ + public async hasPeersWithMaintain( + options: Partial = {} + ): Promise { + const { forceUseAllPeers = false, maxAttempts = 3 } = options; + + log.info( + `Checking for peers. forceUseAllPeers: ${forceUseAllPeers}, maxAttempts: ${maxAttempts}` + ); + + for (let attempts = 0; attempts < maxAttempts; attempts++) { + log.info( + `Attempt ${attempts + 1}/${maxAttempts} to reach required number of peers` + ); + await this.maintainPeers(); + + if (!forceUseAllPeers && this.connectedPeers.length > 0) { + log.info( + `At least one peer connected (${this.connectedPeers.length}), not forcing use of all peers` + ); + return true; + } + + if (this.connectedPeers.length >= this.numPeersToUse) { + log.info(`Required number of peers (${this.numPeersToUse}) reached`); + return true; + } + + log.warn( + `Found only ${this.connectedPeers.length}/${this.numPeersToUse} required peers. Retrying...` + ); + } + + log.error( + `Failed to find required number of peers (${this.numPeersToUse}) after ${maxAttempts} attempts` + ); + return false; + } + + /** + * Starts an interval to maintain the peers list to `numPeersToUse`. + * @param interval The interval in milliseconds to maintain the peers. + */ + private async startMaintainPeersInterval(interval: number): Promise { + log.info(`Starting maintain peers interval with ${interval}ms interval`); + try { + this.maintainPeersIntervalId = setInterval(() => { + log.info("Running scheduled peer maintenance"); + this.maintainPeers().catch((error) => { + log.error("Error during scheduled peer maintenance:", error); + }); + }, interval); + log.info("Maintain peers interval started successfully"); + } catch (error) { + log.error("Error starting maintain peers interval:", error); + throw error; + } + } + + /** + * Maintains the peers list to `numPeersToUse`. + */ + private async maintainPeers(): Promise { + try { + const currentPeerCount = await this.getPeerCount(); + const numPeersToAdd = this.numPeersToUse - currentPeerCount; + + log.info( + `Current peer count: ${currentPeerCount}, target: ${this.numPeersToUse}` + ); + + if (numPeersToAdd === 0) { + log.info("Peer count is at target, no maintenance required"); + return; + } + + if (numPeersToAdd > 0) { + log.info(`Attempting to add ${numPeersToAdd} peer(s)`); + await this.findAndAddPeers(numPeersToAdd); + } else { + log.info( + `Attempting to remove ${Math.abs(numPeersToAdd)} excess peer(s)` + ); + await this.removeExcessPeers(Math.abs(numPeersToAdd)); + } + + const finalPeerCount = await this.getPeerCount(); + log.info( + `Peer maintenance completed. Initial count: ${currentPeerCount}, Final count: ${finalPeerCount}` + ); + } catch (error) { + log.error("Error during peer maintenance", { error }); + } + } public getWriteLockHolder(): string | null { return this.writeLockHolder; } - public getPeers(): Peer[] { + public get connectedPeers(): Peer[] { return Array.from(this.peers.values()); } + public getPeers(): Peer[] { + return this.connectedPeers.slice(0, this.numPeersToUse); + } + public async addPeer(peer: Peer): Promise { return this.writeMutex.runExclusive(async () => { this.writeLockHolder = `addPeer: ${peer.id.toString()}`; diff --git a/packages/sdk/src/protocols/store/index.ts b/packages/sdk/src/protocols/store/index.ts index 36249a0f2f..cd8029618b 100644 --- a/packages/sdk/src/protocols/store/index.ts +++ b/packages/sdk/src/protocols/store/index.ts @@ -10,29 +10,23 @@ import { import { messageHash } from "@waku/message-hash"; import { ensurePubsubTopicIsConfigured, isDefined, Logger } from "@waku/utils"; -import { BaseProtocolSDK } from "../base_protocol.js"; import { PeerManager } from "../peer_manager.js"; -const DEFAULT_NUM_PEERS = 1; - const log = new Logger("waku:store:sdk"); /** * StoreSDK is an implementation of the IStoreSDK interface. * It provides methods to interact with the Waku Store protocol. */ -export class Store extends BaseProtocolSDK implements IStore { +export class Store implements IStore { public readonly protocol: StoreCore; public constructor( - private connectionManager: ConnectionManager, + connectionManager: ConnectionManager, libp2p: Libp2p, - peerManager: PeerManager + private peerManager: PeerManager ) { - super(new StoreCore(connectionManager.pubsubTopics, libp2p), peerManager, { - numPeersToUse: DEFAULT_NUM_PEERS - }); - this.protocol = this.core as StoreCore; + this.protocol = new StoreCore(connectionManager.pubsubTopics, libp2p); } /** @@ -59,9 +53,7 @@ export class Store extends BaseProtocolSDK implements IStore { ...options }; - const peers = await this.connectionManager.getConnectedPeers( - this.core.multicodec - ); + const peers = this.peerManager.getPeers(); const peer = peers[0]; if (!peer) { diff --git a/packages/sdk/src/waku/waku.ts b/packages/sdk/src/waku/waku.ts index 90572896d9..c4cdabae3a 100644 --- a/packages/sdk/src/waku/waku.ts +++ b/packages/sdk/src/waku/waku.ts @@ -83,7 +83,12 @@ export class WakuNode implements IWaku { config: options?.connectionManager }); - this.peerManager = new PeerManager(this.connectionManager); + this.peerManager = new PeerManager({ + config: { + numPeersToUse: options.numPeersToUse + }, + connectionManager: this.connectionManager + }); this.health = getHealthManager(); @@ -93,7 +98,7 @@ export class WakuNode implements IWaku { } if (protocolsEnabled.lightpush) { - const lightPush = wakuLightPush(this.connectionManager, options); + const lightPush = wakuLightPush(this.connectionManager, this.peerManager); this.lightPush = lightPush(libp2p); } @@ -101,8 +106,7 @@ export class WakuNode implements IWaku { const filter = wakuFilter( this.connectionManager, this.peerManager, - this.lightPush, - options + this.lightPush ); this.filter = filter(libp2p); } From d0c6905005f881ee592b351929e6c03296399477 Mon Sep 17 00:00:00 2001 From: Sasha Date: Thu, 24 Oct 2024 01:18:25 +0200 Subject: [PATCH 09/12] re-implement peerManager, remove ProtocolUseOptions --- packages/core/src/lib/light_push/index.ts | 1 + packages/interfaces/src/filter.ts | 2 - packages/interfaces/src/protocols.ts | 15 - packages/sdk/package.json | 1 - packages/sdk/src/protocols/filter/index.ts | 27 +- .../protocols/filter/subscription_manager.ts | 27 +- .../src/protocols/light_push/light_push.ts | 4 +- packages/sdk/src/protocols/peer_manager.ts | 278 ++++-------------- packages/sdk/src/protocols/store/index.ts | 2 +- packages/sdk/src/reliability_monitor/index.ts | 13 +- .../sdk/src/reliability_monitor/receiver.ts | 18 +- packages/sdk/src/waku/waku.ts | 5 +- 12 files changed, 104 insertions(+), 289 deletions(-) diff --git a/packages/core/src/lib/light_push/index.ts b/packages/core/src/lib/light_push/index.ts index 440201464f..d649df7a21 100644 --- a/packages/core/src/lib/light_push/index.ts +++ b/packages/core/src/lib/light_push/index.ts @@ -76,6 +76,7 @@ export class LightPushCore extends BaseProtocol implements IBaseProtocolCore { } } + // TODO(weboko): use peer.id as parameter instead public async send( encoder: IEncoder, message: IMessage, diff --git a/packages/interfaces/src/filter.ts b/packages/interfaces/src/filter.ts index 373aac5121..f992a497a7 100644 --- a/packages/interfaces/src/filter.ts +++ b/packages/interfaces/src/filter.ts @@ -6,7 +6,6 @@ import type { Callback, IBaseProtocolCore, ProtocolError, - ProtocolUseOptions, SDKProtocolResult } from "./protocols.js"; import type { IReceiver } from "./receiver.js"; @@ -40,7 +39,6 @@ export type IFilter = IReceiver & { protocol: IBaseProtocolCore } & { subscribe( decoders: IDecoder | IDecoder[], callback: Callback, - protocolUseOptions?: ProtocolUseOptions, subscribeOptions?: SubscribeOptions ): Promise; }; diff --git a/packages/interfaces/src/protocols.ts b/packages/interfaces/src/protocols.ts index 42e4708911..00d330152e 100644 --- a/packages/interfaces/src/protocols.ts +++ b/packages/interfaces/src/protocols.ts @@ -22,21 +22,6 @@ export type IBaseProtocolCore = { export type NetworkConfig = StaticSharding | AutoSharding; -//TODO: merge this with ProtocolCreateOptions or establish distinction: https://github.com/waku-org/js-waku/issues/2048 -/** - * Options for using LightPush and Filter - */ -export type ProtocolUseOptions = { - /** - * Optional flag to force using all available peers - */ - forceUseAllPeers?: boolean; - /** - * Optional maximum number of attempts for exponential backoff - */ - maxAttempts?: number; -}; - export type ProtocolCreateOptions = { /** * Configuration for determining the network in use. diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 086024363e..aabe7ab68e 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -73,7 +73,6 @@ "@waku/proto": "^0.0.8", "@waku/utils": "0.0.21", "@waku/message-hash": "0.1.17", - "async-mutex": "^0.5.0", "libp2p": "^1.8.1" }, "devDependencies": { diff --git a/packages/sdk/src/protocols/filter/index.ts b/packages/sdk/src/protocols/filter/index.ts index d0cfa50a44..a70e484793 100644 --- a/packages/sdk/src/protocols/filter/index.ts +++ b/packages/sdk/src/protocols/filter/index.ts @@ -10,7 +10,6 @@ import { type Libp2p, NetworkConfig, ProtocolError, - type ProtocolUseOptions, type PubsubTopic, type SubscribeOptions, SubscribeResult, @@ -67,7 +66,6 @@ class Filter implements IFilter { * * @param {IDecoder | IDecoder[]} decoders - A single decoder or an array of decoders to use for decoding messages. * @param {Callback} callback - The callback function to be invoked with decoded messages. - * @param {ProtocolUseOptions} [protocolUseOptions] - Optional settings for using the protocol. * @param {SubscribeOptions} [subscribeOptions=DEFAULT_SUBSCRIBE_OPTIONS] - Options for the subscription. * * @returns {Promise} A promise that resolves to an object containing: @@ -103,7 +101,6 @@ class Filter implements IFilter { public async subscribe( decoders: IDecoder | IDecoder[], callback: Callback, - protocolUseOptions?: ProtocolUseOptions, subscribeOptions: SubscribeOptions = DEFAULT_SUBSCRIBE_OPTIONS ): Promise { const uniquePubsubTopics = this.getUniquePubsubTopics(decoders); @@ -118,10 +115,7 @@ class Filter implements IFilter { const pubsubTopic = uniquePubsubTopics[0]; - const { subscription, error } = await this.createSubscription( - pubsubTopic, - protocolUseOptions - ); + const { subscription, error } = await this.createSubscription(pubsubTopic); if (error) { return { @@ -153,14 +147,8 @@ class Filter implements IFilter { * @returns The subscription object. */ private async createSubscription( - pubsubTopicShardInfo: NetworkConfig | PubsubTopic, - options?: ProtocolUseOptions + pubsubTopicShardInfo: NetworkConfig | PubsubTopic ): Promise { - options = { - autoRetry: true, - ...options - } as ProtocolUseOptions; - const pubsubTopic = typeof pubsubTopicShardInfo == "string" ? pubsubTopicShardInfo @@ -168,8 +156,8 @@ class Filter implements IFilter { ensurePubsubTopicIsConfigured(pubsubTopic, this.protocol.pubsubTopics); - const hasPeers = await this.peerManager.hasPeersWithMaintain(options); - if (!hasPeers) { + const peers = await this.peerManager.getPeers(); + if (peers.length === 0) { return { error: ProtocolError.NO_PEER_AVAILABLE, subscription: null @@ -177,8 +165,8 @@ class Filter implements IFilter { } log.info( - `Creating filter subscription with ${this.peerManager.connectedPeers.length} peers: `, - this.peerManager.connectedPeers.map((peer) => peer.id.toString()) + `Creating filter subscription with ${peers.length} peers: `, + peers.map((peer) => peer.id.toString()) ); const subscription = @@ -189,8 +177,7 @@ class Filter implements IFilter { pubsubTopic, this.protocol, this.connectionManager, - () => this.peerManager.connectedPeers, - this.peerManager.renewPeer.bind(this), + this.peerManager, this.libp2p, this.lightPush ) diff --git a/packages/sdk/src/protocols/filter/subscription_manager.ts b/packages/sdk/src/protocols/filter/subscription_manager.ts index 1dc2724ab5..59af175121 100644 --- a/packages/sdk/src/protocols/filter/subscription_manager.ts +++ b/packages/sdk/src/protocols/filter/subscription_manager.ts @@ -30,6 +30,7 @@ import { groupByContentTopic, Logger } from "@waku/utils"; import { ReliabilityMonitorManager } from "../../reliability_monitor/index.js"; import { ReceiverReliabilityMonitor } from "../../reliability_monitor/receiver.js"; +import { PeerManager } from "../peer_manager.js"; import { DEFAULT_KEEP_ALIVE, @@ -57,10 +58,7 @@ export class SubscriptionManager implements ISubscription { private readonly pubsubTopic: PubsubTopic, private readonly protocol: FilterCore, private readonly connectionManager: ConnectionManager, - private readonly getPeers: () => Peer[], - private readonly renewPeer: ( - peerToDisconnect: PeerId - ) => Promise, + private readonly peerManager: PeerManager, private readonly libp2p: Libp2p, private readonly lightPush?: ILightPush ) { @@ -69,11 +67,9 @@ export class SubscriptionManager implements ISubscription { this.reliabilityMonitor = ReliabilityMonitorManager.createReceiverMonitor( this.pubsubTopic, - this.getPeers.bind(this), - this.renewPeer.bind(this), + this.peerManager, () => Array.from(this.subscriptionCallbacks.keys()), this.protocol.subscribe.bind(this.protocol), - this.protocol.addLibp2pEventListener.bind(this.protocol), this.sendLightPushCheckMessage.bind(this) ); } @@ -116,7 +112,8 @@ export class SubscriptionManager implements ISubscription { const decodersGroupedByCT = groupByContentTopic(decodersArray); const contentTopics = Array.from(decodersGroupedByCT.keys()); - const promises = this.getPeers().map(async (peer) => + const peers = await this.peerManager.getPeers(); + const promises = peers.map(async (peer) => this.subscribeWithPeerVerification(peer, contentTopics) ); @@ -153,7 +150,8 @@ export class SubscriptionManager implements ISubscription { public async unsubscribe( contentTopics: ContentTopic[] ): Promise { - const promises = this.getPeers().map(async (peer) => { + const peers = await this.peerManager.getPeers(); + const promises = peers.map(async (peer) => { const response = await this.protocol.unsubscribe( this.pubsubTopic, peer, @@ -179,7 +177,9 @@ export class SubscriptionManager implements ISubscription { public async ping(peerId?: PeerId): Promise { log.info("Sending keep-alive ping"); - const peers = peerId ? [peerId] : this.getPeers().map((peer) => peer.id); + const peers = peerId + ? [peerId] + : (await this.peerManager.getPeers()).map((peer) => peer.id); const promises = peers.map((peerId) => this.pingSpecificPeer(peerId)); const results = await Promise.allSettled(promises); @@ -188,7 +188,8 @@ export class SubscriptionManager implements ISubscription { } public async unsubscribeAll(): Promise { - const promises = this.getPeers().map(async (peer) => + const peers = await this.peerManager.getPeers(); + const promises = peers.map(async (peer) => this.protocol.unsubscribeAll(this.pubsubTopic, peer) ); @@ -241,6 +242,7 @@ export class SubscriptionManager implements ISubscription { peer, contentTopics ); + await this.sendLightPushCheckMessage(peer); return result; } @@ -271,7 +273,8 @@ export class SubscriptionManager implements ISubscription { } private async pingSpecificPeer(peerId: PeerId): Promise { - const peer = this.getPeers().find((p) => p.id.equals(peerId)); + const peers = await this.peerManager.getPeers(); + const peer = peers.find((p) => p.id.equals(peerId)); if (!peer) { return { success: null, diff --git a/packages/sdk/src/protocols/light_push/light_push.ts b/packages/sdk/src/protocols/light_push/light_push.ts index fb1ca55d22..f04f3175b6 100644 --- a/packages/sdk/src/protocols/light_push/light_push.ts +++ b/packages/sdk/src/protocols/light_push/light_push.ts @@ -59,7 +59,7 @@ export class LightPush implements ILightPush { }; } - const peers = this.peerManager.getPeers(); + const peers = await this.peerManager.getPeers(); if (peers.length === 0) { return { successes, @@ -117,7 +117,7 @@ export class LightPush implements ILightPush { maxAttempts?: number ): Promise { maxAttempts = maxAttempts || DEFAULT_MAX_ATTEMPTS; - const connectedPeers = this.peerManager.getPeers(); + const connectedPeers = await this.peerManager.getPeers(); if (connectedPeers.length === 0) { log.warn("Cannot retry with no connected peers."); diff --git a/packages/sdk/src/protocols/peer_manager.ts b/packages/sdk/src/protocols/peer_manager.ts index 4d9b98a4d5..c4d26d9ae4 100644 --- a/packages/sdk/src/protocols/peer_manager.ts +++ b/packages/sdk/src/protocols/peer_manager.ts @@ -1,271 +1,123 @@ -import { Peer, PeerId } from "@libp2p/interface"; -import { ConnectionManager } from "@waku/core"; -import { ProtocolUseOptions } from "@waku/interfaces"; +import { Connection, Peer, PeerId } from "@libp2p/interface"; +import { Libp2p } from "@waku/interfaces"; import { Logger } from "@waku/utils"; -import { Mutex } from "async-mutex"; const log = new Logger("peer-manager"); const DEFAULT_NUM_PEERS_TO_USE = 2; -const DEFAULT_MAINTAIN_PEERS_INTERVAL = 30_000; +const CONNECTION_LOCK_TAG = "peer-manager-lock"; type PeerManagerConfig = { numPeersToUse?: number; - maintainPeersIntervalMs?: number; }; type PeerManagerParams = { + libp2p: Libp2p; config?: PeerManagerConfig; - connectionManager: ConnectionManager; }; export class PeerManager { - private peers: Map = new Map(); - - private readMutex = new Mutex(); - private writeMutex = new Mutex(); - private writeLockHolder: string | null = null; - private readonly numPeersToUse: number; - private readonly maintainPeersIntervalMs: number; - private readonly connectionManager: ConnectionManager; - private maintainPeersIntervalId: ReturnType< - typeof window.setInterval - > | null = null; + private readonly libp2p: Libp2p; public constructor(params: PeerManagerParams) { this.numPeersToUse = params?.config?.numPeersToUse || DEFAULT_NUM_PEERS_TO_USE; - this.maintainPeersIntervalMs = - params?.config?.maintainPeersIntervalMs || - DEFAULT_MAINTAIN_PEERS_INTERVAL; - this.connectionManager = params.connectionManager; + this.libp2p = params.libp2p; - void this.startMaintainPeersInterval(this.maintainPeersIntervalMs); + this.startConnectionListener(); } - /** - * Disconnects from a peer and tries to find a new one to replace it. - * @param peerToDisconnect The peer to disconnect from. - * @returns The new peer that was found and connected to. - */ - public async renewPeer(peerToDisconnect: PeerId): Promise { - log.info(`Attempting to renew peer ${peerToDisconnect}`); - - const newPeer = await this.findPeers(1); - if (newPeer.length === 0) { - log.error("Failed to find a new peer to replace the disconnected one"); - return undefined; - } - - await this.removePeer(peerToDisconnect); - await this.addPeer(newPeer[0]); - - log.info(`Successfully renewed peer. New peer: ${newPeer[0].id}`); - - return newPeer[0]; + public stop(): void { + this.stopConnectionListener(); } - /** - * Stops the maintain peers interval. - */ - public stopMaintainPeersInterval(): void { - if (this.maintainPeersIntervalId) { - clearInterval(this.maintainPeersIntervalId); - this.maintainPeersIntervalId = null; - log.info("Maintain peers interval stopped"); - } else { - log.info("Maintain peers interval was not running"); - } - } - - /** - * Checks if there are sufficient peers to send a message to. - * If `forceUseAllPeers` is `false` (default), returns `true` if there are any connected peers. - * If `forceUseAllPeers` is `true`, attempts to connect to `numPeersToUse` peers. - * @param options Optional options object - * @param options.forceUseAllPeers Optional flag to force connecting to `numPeersToUse` peers (default: false) - * @param options.maxAttempts Optional maximum number of attempts to reach the required number of peers (default: 3) - * @returns `true` if the required number of peers are connected, `false` otherwise - */ - public async hasPeersWithMaintain( - options: Partial = {} - ): Promise { - const { forceUseAllPeers = false, maxAttempts = 3 } = options; - - log.info( - `Checking for peers. forceUseAllPeers: ${forceUseAllPeers}, maxAttempts: ${maxAttempts}` + public async getPeers(): Promise { + return Promise.all( + this.getLockedConnections().map((c) => this.mapConnectionToPeer(c)) ); + } - for (let attempts = 0; attempts < maxAttempts; attempts++) { - log.info( - `Attempt ${attempts + 1}/${maxAttempts} to reach required number of peers` - ); - await this.maintainPeers(); - - if (!forceUseAllPeers && this.connectedPeers.length > 0) { - log.info( - `At least one peer connected (${this.connectedPeers.length}), not forcing use of all peers` - ); - return true; - } - - if (this.connectedPeers.length >= this.numPeersToUse) { - log.info(`Required number of peers (${this.numPeersToUse}) reached`); - return true; - } + public async requestRenew( + peerId: PeerId | string + ): Promise { + const lockedConnections = this.getLockedConnections(); + const neededPeers = this.numPeersToUse - lockedConnections.length; - log.warn( - `Found only ${this.connectedPeers.length}/${this.numPeersToUse} required peers. Retrying...` - ); + if (neededPeers === 0) { + return; } - log.error( - `Failed to find required number of peers (${this.numPeersToUse}) after ${maxAttempts} attempts` + const result = await Promise.all( + this.getUnlockedConnections() + .filter((c) => !c.remotePeer.equals(peerId)) + .slice(0, neededPeers) + .map((c) => this.lockConnection(c)) + .map((c) => this.mapConnectionToPeer(c)) ); - return false; - } - /** - * Starts an interval to maintain the peers list to `numPeersToUse`. - * @param interval The interval in milliseconds to maintain the peers. - */ - private async startMaintainPeersInterval(interval: number): Promise { - log.info(`Starting maintain peers interval with ${interval}ms interval`); - try { - this.maintainPeersIntervalId = setInterval(() => { - log.info("Running scheduled peer maintenance"); - this.maintainPeers().catch((error) => { - log.error("Error during scheduled peer maintenance:", error); - }); - }, interval); - log.info("Maintain peers interval started successfully"); - } catch (error) { - log.error("Error starting maintain peers interval:", error); - throw error; - } + return result[0]; } - /** - * Maintains the peers list to `numPeersToUse`. - */ - private async maintainPeers(): Promise { - try { - const currentPeerCount = await this.getPeerCount(); - const numPeersToAdd = this.numPeersToUse - currentPeerCount; - - log.info( - `Current peer count: ${currentPeerCount}, target: ${this.numPeersToUse}` - ); - - if (numPeersToAdd === 0) { - log.info("Peer count is at target, no maintenance required"); - return; - } - - if (numPeersToAdd > 0) { - log.info(`Attempting to add ${numPeersToAdd} peer(s)`); - await this.findAndAddPeers(numPeersToAdd); - } else { - log.info( - `Attempting to remove ${Math.abs(numPeersToAdd)} excess peer(s)` - ); - await this.removeExcessPeers(Math.abs(numPeersToAdd)); - } - - const finalPeerCount = await this.getPeerCount(); - log.info( - `Peer maintenance completed. Initial count: ${currentPeerCount}, Final count: ${finalPeerCount}` - ); - } catch (error) { - log.error("Error during peer maintenance", { error }); - } + private startConnectionListener(): void { + this.libp2p.addEventListener("peer:connect", this.onConnected); + this.libp2p.addEventListener("peer:disconnect", this.onDisconnected); } - public getWriteLockHolder(): string | null { - return this.writeLockHolder; + private stopConnectionListener(): void { + this.libp2p.removeEventListener("peer:connect", this.onConnected); + this.libp2p.removeEventListener("peer:disconnect", this.onDisconnected); } - public get connectedPeers(): Peer[] { - return Array.from(this.peers.values()); + private onConnected(event: CustomEvent): void { + const peerId = event.detail; + void this.lockPeerIfNeeded(peerId); } - public getPeers(): Peer[] { - return this.connectedPeers.slice(0, this.numPeersToUse); + private onDisconnected(event: CustomEvent): void { + const peerId = event.detail; + void this.requestRenew(peerId); } - public async addPeer(peer: Peer): Promise { - return this.writeMutex.runExclusive(async () => { - this.writeLockHolder = `addPeer: ${peer.id.toString()}`; - await this.connectionManager.attemptDial(peer.id); - this.peers.set(peer.id.toString(), peer); - log.info(`Added and dialed peer: ${peer.id.toString()}`); - this.writeLockHolder = null; - }); - } + private async lockPeerIfNeeded(peerId: PeerId): Promise { + const lockedConnections = this.getLockedConnections(); + const neededPeers = this.numPeersToUse - lockedConnections.length; - public async removePeer(peerId: PeerId): Promise { - return this.writeMutex.runExclusive(() => { - this.writeLockHolder = `removePeer: ${peerId.toString()}`; - this.peers.delete(peerId.toString()); - log.info(`Removed peer: ${peerId.toString()}`); - this.writeLockHolder = null; - }); - } + if (neededPeers === 0) { + return; + } - public async getPeerCount(): Promise { - return this.readMutex.runExclusive(() => this.peers.size); + this.getUnlockedConnections() + .filter((c) => c.remotePeer.equals(peerId)) + .map((c) => this.lockConnection(c)); } - public async hasPeers(): Promise { - return this.readMutex.runExclusive(() => this.peers.size > 0); + private getLockedConnections(): Connection[] { + return this.libp2p + .getConnections() + .filter((c) => c.status === "open" && this.isConnectionLocked(c)); } - public async removeExcessPeers(excessPeers: number): Promise { - log.info(`Removing ${excessPeers} excess peer(s)`); - const peersToRemove = Array.from(this.peers.values()).slice(0, excessPeers); - for (const peer of peersToRemove) { - await this.removePeer(peer.id); - } + private getUnlockedConnections(): Connection[] { + return this.libp2p + .getConnections() + .filter((c) => c.status === "open" && !this.isConnectionLocked(c)); } - /** - * Finds and adds new peers to the peers list. - * @param numPeers The number of peers to find and add. - */ - public async findAndAddPeers(numPeers: number): Promise { - const additionalPeers = await this.findPeers(numPeers); - if (additionalPeers.length === 0) { - log.warn("No additional peers found"); - return []; - } - return this.addMultiplePeers(additionalPeers); + private lockConnection(c: Connection): Connection { + log.info(`Locking connection for peerId=${c.remotePeer.toString()}`); + c.tags.push(CONNECTION_LOCK_TAG); + return c; } - /** - * Finds additional peers. - * @param numPeers The number of peers to find. - */ - public async findPeers(numPeers: number): Promise { - const connectedPeers = await this.connectionManager.getConnectedPeers(); - - return this.readMutex.runExclusive(async () => { - const newPeers = connectedPeers - .filter((peer) => !this.peers.has(peer.id.toString())) - .slice(0, numPeers); - - return newPeers; - }); + private isConnectionLocked(c: Connection): boolean { + return c.tags.includes(CONNECTION_LOCK_TAG); } - public async addMultiplePeers(peers: Peer[]): Promise { - const addedPeers: Peer[] = []; - for (const peer of peers) { - await this.addPeer(peer); - addedPeers.push(peer); - } - return addedPeers; + private async mapConnectionToPeer(c: Connection): Promise { + const peerId = c.remotePeer; + return this.libp2p.peerStore.get(peerId); } } diff --git a/packages/sdk/src/protocols/store/index.ts b/packages/sdk/src/protocols/store/index.ts index cd8029618b..01cfd277eb 100644 --- a/packages/sdk/src/protocols/store/index.ts +++ b/packages/sdk/src/protocols/store/index.ts @@ -53,7 +53,7 @@ export class Store implements IStore { ...options }; - const peers = this.peerManager.getPeers(); + const peers = await this.peerManager.getPeers(); const peer = peers[0]; if (!peer) { diff --git a/packages/sdk/src/reliability_monitor/index.ts b/packages/sdk/src/reliability_monitor/index.ts index f92d1fa866..120d208404 100644 --- a/packages/sdk/src/reliability_monitor/index.ts +++ b/packages/sdk/src/reliability_monitor/index.ts @@ -1,11 +1,12 @@ -import type { Peer, PeerId } from "@libp2p/interface"; +import type { Peer } from "@libp2p/interface"; import { ContentTopic, CoreProtocolResult, - Libp2p, PubsubTopic } from "@waku/interfaces"; +import { PeerManager } from "../protocols/peer_manager.js"; + import { ReceiverReliabilityMonitor } from "./receiver.js"; export class ReliabilityMonitorManager { @@ -16,15 +17,13 @@ export class ReliabilityMonitorManager { public static createReceiverMonitor( pubsubTopic: PubsubTopic, - getPeers: () => Peer[], - renewPeer: (peerId: PeerId) => Promise, + peerManager: PeerManager, getContentTopics: () => ContentTopic[], protocolSubscribe: ( pubsubTopic: PubsubTopic, peer: Peer, contentTopics: ContentTopic[] ) => Promise, - addLibp2pEventListener: Libp2p["addEventListener"], sendLightPushMessage: (peer: Peer) => Promise ): ReceiverReliabilityMonitor { if (ReliabilityMonitorManager.receiverMonitors.has(pubsubTopic)) { @@ -33,11 +32,9 @@ export class ReliabilityMonitorManager { const monitor = new ReceiverReliabilityMonitor( pubsubTopic, - getPeers, - renewPeer, + peerManager, getContentTopics, protocolSubscribe, - addLibp2pEventListener, sendLightPushMessage ); ReliabilityMonitorManager.receiverMonitors.set(pubsubTopic, monitor); diff --git a/packages/sdk/src/reliability_monitor/receiver.ts b/packages/sdk/src/reliability_monitor/receiver.ts index ea58c1b17c..6e2c6d59dc 100644 --- a/packages/sdk/src/reliability_monitor/receiver.ts +++ b/packages/sdk/src/reliability_monitor/receiver.ts @@ -3,7 +3,6 @@ import { ContentTopic, CoreProtocolResult, IProtoMessage, - Libp2p, PeerIdStr, PubsubTopic } from "@waku/interfaces"; @@ -11,6 +10,8 @@ import { messageHashStr } from "@waku/message-hash"; import { Logger } from "@waku/utils"; import { bytesToUtf8 } from "@waku/utils/bytes"; +import { PeerManager } from "../protocols/peer_manager.js"; + const log = new Logger("sdk:receiver:reliability_monitor"); const DEFAULT_MAX_PINGS = 3; @@ -28,24 +29,15 @@ export class ReceiverReliabilityMonitor { public constructor( private readonly pubsubTopic: PubsubTopic, - private getPeers: () => Peer[], - private renewPeer: (peerId: PeerId) => Promise, + private readonly peerManager: PeerManager, private getContentTopics: () => ContentTopic[], private protocolSubscribe: ( pubsubTopic: PubsubTopic, peer: Peer, contentTopics: ContentTopic[] ) => Promise, - private addLibp2pEventListener: Libp2p["addEventListener"], private sendLightPushMessage: (peer: Peer) => Promise - ) { - this.addLibp2pEventListener("peer:disconnect", (evt) => { - const peerId = evt.detail; - if (this.getPeers().some((p) => p.id.equals(peerId))) { - void this.renewAndSubscribePeer(peerId); - } - }); - } + ) {} public setMaxPingFailures(value: number | undefined): void { if (value === undefined) { @@ -166,7 +158,7 @@ export class ReceiverReliabilityMonitor { this.peerRenewalLocks.add(peerIdStr); - const newPeer = await this.renewPeer(peerId); + const newPeer = await this.peerManager.requestRenew(peerId); if (!newPeer) { log.warn(`Failed to renew peer ${peerIdStr}: No new peer found.`); return; diff --git a/packages/sdk/src/waku/waku.ts b/packages/sdk/src/waku/waku.ts index c4cdabae3a..96706e1a13 100644 --- a/packages/sdk/src/waku/waku.ts +++ b/packages/sdk/src/waku/waku.ts @@ -84,10 +84,10 @@ export class WakuNode implements IWaku { }); this.peerManager = new PeerManager({ + libp2p, config: { numPeersToUse: options.numPeersToUse - }, - connectionManager: this.connectionManager + } }); this.health = getHealthManager(); @@ -192,6 +192,7 @@ export class WakuNode implements IWaku { public async stop(): Promise { ReliabilityMonitorManager.stopAll(); + this.peerManager.stop(); this.connectionManager.stop(); await this.libp2p.stop(); } From 984326bb53ef278e9eae1e3b9b1784e59a74470b Mon Sep 17 00:00:00 2001 From: Sasha Date: Thu, 24 Oct 2024 01:58:44 +0200 Subject: [PATCH 10/12] remove not needed test, up lock --- package-lock.json | 1690 +++++++---------- .../tests/filter/peer_management.spec.ts | 323 ---- 2 files changed, 714 insertions(+), 1299 deletions(-) delete mode 100644 packages/tests/tests/filter/peer_management.spec.ts diff --git a/package-lock.json b/package-lock.json index 4501ba8551..518f07b4c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -81,12 +81,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.7.tgz", - "integrity": "sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.25.9.tgz", + "integrity": "sha512-z88xeGxnzehn2sqZ8UdGQEvYErF1odv2CftxInpSYJt6uHuPe9YjahKZITGs3l5LeI9d2ROG+obuDAoSlqbNfQ==", "license": "MIT", "dependencies": { - "@babel/highlight": "^7.25.7", + "@babel/highlight": "^7.25.9", "picocolors": "^1.0.0" }, "engines": { @@ -94,30 +94,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.8.tgz", - "integrity": "sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.9.tgz", + "integrity": "sha512-yD+hEuJ/+wAJ4Ox2/rpNv5HIuPG82x3ZlQvYVn8iYCprdxzE7P1udpGF1jyjQVBU4dgznN+k2h103vxZ7NdPyw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.8.tgz", - "integrity": "sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.9.tgz", + "integrity": "sha512-WYvQviPw+Qyib0v92AwNIrdLISTp7RfDkM7bPqBvpbnhY4wq8HvHBZREVdYDXk98C8BkOIVnHAY3yvj7AVISxQ==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helpers": "^7.25.7", - "@babel/parser": "^7.25.8", - "@babel/template": "^7.25.7", - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.8", + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helpers": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -154,12 +154,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.7.tgz", - "integrity": "sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.9.tgz", + "integrity": "sha512-omlUGkr5EaoIJrhLf9CJ0TvjBRpd9+AXRG//0GEQ9THSo8wPiTlbpy1/Ow8ZTrbXpjd9FHXfbFQx32I04ht0FA==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.7", + "@babel/types": "^7.25.9", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^3.0.2" @@ -179,38 +179,38 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz", - "integrity": "sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz", - "integrity": "sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.9.tgz", + "integrity": "sha512-C47lC7LIDCnz0h4vai/tpNOI95tCd5ZT3iBt/DBH5lXKHZsyNQv18yf1wIIg2ntiQNgmAvA+DgZ82iW8Qdym8g==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz", - "integrity": "sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.9.tgz", + "integrity": "sha512-j9Db8Suy6yV/VHa4qzrj9yZfZxhLWQdVnRlXxmKLYlhWUVB1sB2G5sxuWYXk/whHD9iW76PmNzxZ4UCnTQTVEQ==", "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", + "@babel/compat-data": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -244,17 +244,17 @@ "license": "ISC" }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz", - "integrity": "sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", - "@babel/helper-member-expression-to-functions": "^7.25.7", - "@babel/helper-optimise-call-expression": "^7.25.7", - "@babel/helper-replace-supers": "^7.25.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", - "@babel/traverse": "^7.25.7", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", "semver": "^6.3.1" }, "engines": { @@ -274,12 +274,12 @@ } }, "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz", - "integrity": "sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.9.tgz", + "integrity": "sha512-ORPNZ3h6ZRkOyAa/SaHU+XsLZr0UQzRwuDQ0cczIA17nAzZ+85G5cVkOJIj7QavLZGSe8QXUmNFxSZzjcZF9bw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", + "@babel/helper-annotate-as-pure": "^7.25.9", "regexpu-core": "^6.1.1", "semver": "^6.3.1" }, @@ -328,41 +328,41 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz", - "integrity": "sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz", - "integrity": "sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw==", + "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", "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz", - "integrity": "sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.9.tgz", + "integrity": "sha512-TvLZY/F3+GvdRYFZFyxMvnsKi+4oJdgZzU3BoGN9Uc2d9C6zfNwJcKKhjqLAhK8i46mv93jsO74fDh3ih6rpHA==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-simple-access": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -372,35 +372,35 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz", - "integrity": "sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz", - "integrity": "sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz", - "integrity": "sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", + "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", - "@babel/helper-wrap-function": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-wrap-function": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -410,14 +410,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz", - "integrity": "sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.7", - "@babel/helper-optimise-call-expression": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -427,92 +427,92 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz", - "integrity": "sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.25.9.tgz", + "integrity": "sha512-c6WHXuiaRsJTyHYLJV75t9IqsmTbItYfdj99PnzYGQZkYKvan5/2jKJ7gu31J3/BJ/A18grImSPModuyG/Eo0Q==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz", - "integrity": "sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz", - "integrity": "sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g==", + "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==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz", - "integrity": "sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz", - "integrity": "sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", + "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-wrap-function": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz", - "integrity": "sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", + "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", "license": "MIT", "dependencies": { - "@babel/template": "^7.25.7", - "@babel/traverse": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz", - "integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.9.tgz", + "integrity": "sha512-oKWp3+usOJSzDZOucZUAMayhPz/xVjzymyDzUN8dk0Wd3RWMlGLXi07UCQ/CgQVb8LvXx3XBajJH4XGgkt7H7g==", "license": "MIT", "dependencies": { - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.7.tgz", - "integrity": "sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.25.9.tgz", + "integrity": "sha512-llL88JShoCsth8fF8R4SJnIn+WLvR6ccFxu1H3FlMhDontdcmZWf2HgIZ7AIqV3Xcck1idlohrN4EUBQz6klbw==", "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.7", + "@babel/helper-validator-identifier": "^7.25.9", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -593,12 +593,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.8.tgz", - "integrity": "sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.9.tgz", + "integrity": "sha512-aI3jjAAO1fh7vY/pBGsn1i9LDbRP43+asrRlkPuTXW5yHXtd1NgTEMudbBoDDxrf1daEEfPJqR+JBMakzrR4Dg==", "license": "MIT", "dependencies": { - "@babel/types": "^7.25.8" + "@babel/types": "^7.25.9" }, "bin": { "parser": "bin/babel-parser.js" @@ -608,14 +608,14 @@ } }, "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz", - "integrity": "sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.9.tgz", + "integrity": "sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -625,13 +625,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz", - "integrity": "sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.9.tgz", + "integrity": "sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -641,13 +641,13 @@ } }, "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz", - "integrity": "sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.9.tgz", + "integrity": "sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -657,15 +657,15 @@ } }, "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz", - "integrity": "sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", - "@babel/plugin-transform-optional-chaining": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -675,14 +675,14 @@ } }, "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz", - "integrity": "sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.9.tgz", + "integrity": "sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -728,15 +728,15 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.7.tgz", - "integrity": "sha512-q1mqqqH0e1lhmsEQHV5U8OmdueBC2y0RFr2oUzZoFRtN3MvPmt2fsFRcNQAoGLTSNdHBFUYGnlgcRFhkBbKjPw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.9.tgz", + "integrity": "sha512-smkNLL/O1ezy9Nhy4CNosc4Va+1wo5w4gzSZeLe6y6dM4mmHfYOCPolXQPHQxonZCF+ZyebxN9vqOolkYrSn5g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-decorators": "^7.25.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-decorators": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -746,12 +746,12 @@ } }, "node_modules/@babel/plugin-proposal-export-default-from": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.25.8.tgz", - "integrity": "sha512-5SLPHA/Gk7lNdaymtSVS9jH77Cs7yuHTR3dYj+9q+M7R7tNLXhNuvnmOfafRIzpWL+dtMibuu1I4ofrc768Gkw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.25.9.tgz", + "integrity": "sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -893,13 +893,13 @@ } }, "node_modules/@babel/plugin-syntax-decorators": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.7.tgz", - "integrity": "sha512-oXduHo642ZhstLVYTe2z2GSJIruU0c/W3/Ghr6A5yGMsVrvdnxO1z+3pbTcT7f3/Clnt+1z8D/w1r1f1SHaCHw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.9.tgz", + "integrity": "sha512-ryzI0McXUPJnRCvMo4lumIKZUzhYUO/ScI+Mz4YVaTLt04DHNSjEUjKVvbzQjZFLuod/cYEc07mJWhzl6v4DPg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -921,12 +921,12 @@ } }, "node_modules/@babel/plugin-syntax-export-default-from": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.25.7.tgz", - "integrity": "sha512-LRUCsC0YucSjabsmxx6yly8+Q/5mxKdp9gemlpR9ro3bfpcOQOXx/CHivs7QCbjgygd6uQ2GcRfHu1FVax/hgg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.25.9.tgz", + "integrity": "sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -936,12 +936,12 @@ } }, "node_modules/@babel/plugin-syntax-flow": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.25.7.tgz", - "integrity": "sha512-fyoj6/YdVtlv2ROig/J0fP7hh/wNO1MJGm1NR70Pg7jbkF+jOUL9joorqaCOQh06Y+LfgTagHzC8KqZ3MF782w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.25.9.tgz", + "integrity": "sha512-F3FVgxwamIRS3+kfjNaPARX0DSAiH1exrQUVajXiR34hkdA9eyK+8rJbnu55DQjKL/ayuXqjNr2HDXwBEMEtFQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -951,13 +951,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz", - "integrity": "sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.9.tgz", + "integrity": "sha512-4GHX5uzr5QMOOuzV0an9MFju4hKlm0OyePl/lHhcsTVae5t/IKVHnb8W67Vr6FuLlk5lPqLB7n7O+K5R46emYg==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -967,13 +967,13 @@ } }, "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz", - "integrity": "sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.9.tgz", + "integrity": "sha512-u3EN9ub8LyYvgTnrgp8gboElouayiwPdnM7x5tcnW3iSt09/lQYPwMNK40I9IUxo7QOZhAsPHCmmuO7EPdruqg==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -983,12 +983,12 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz", - "integrity": "sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", + "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1071,12 +1071,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz", - "integrity": "sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", + "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1103,12 +1103,12 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz", - "integrity": "sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", + "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1118,15 +1118,15 @@ } }, "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.8.tgz", - "integrity": "sha512-9ypqkozyzpG+HxlH4o4gdctalFGIjjdufzo7I2XPda0iBnZ6a+FO0rIEQcdSPXp02CkvGsII1exJhmROPQd5oA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.9.tgz", + "integrity": "sha512-RXV6QAzTBbhDMO9fWwOmwwTuYaiPbggWQ9INdZqAYeSHyG7FzQ+nOZaUUjNwKv9pV3aE4WFqFm1Hnbci5tBCAw==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-remap-async-to-generator": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1136,14 +1136,14 @@ } }, "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz", - "integrity": "sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.9.tgz", + "integrity": "sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-remap-async-to-generator": "^7.25.7" + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-remap-async-to-generator": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1153,13 +1153,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz", - "integrity": "sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.9.tgz", + "integrity": "sha512-toHc9fzab0ZfenFpsyYinOX0J/5dgJVA2fm64xPewu7CoYHWEivIWKxkK2rMi4r3yQqLnVmheMXRdG+k239CgA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1169,12 +1169,12 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz", - "integrity": "sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.9.tgz", + "integrity": "sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1184,14 +1184,14 @@ } }, "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz", - "integrity": "sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1201,14 +1201,14 @@ } }, "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.8.tgz", - "integrity": "sha512-e82gl3TCorath6YLf9xUwFehVvjvfqFhdOo4+0iVIVju+6XOi5XHkqB3P2AXnSwoeTX0HBoXq5gJFtvotJzFnQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.9.tgz", + "integrity": "sha512-UIf+72C7YJ+PJ685/PpATbCz00XqiFEzHX5iysRwfvNT0Ko+FaXSvRgLytFSp8xUItrG9pFM/KoBBZDrY/cYyg==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1218,16 +1218,16 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz", - "integrity": "sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", + "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-replace-supers": "^7.25.7", - "@babel/traverse": "^7.25.7", + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/traverse": "^7.25.9", "globals": "^11.1.0" }, "engines": { @@ -1247,13 +1247,13 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz", - "integrity": "sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", + "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/template": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/template": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1263,12 +1263,12 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz", - "integrity": "sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", + "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1278,14 +1278,14 @@ } }, "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz", - "integrity": "sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.9.tgz", + "integrity": "sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1295,13 +1295,13 @@ } }, "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz", - "integrity": "sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.9.tgz", + "integrity": "sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1311,14 +1311,14 @@ } }, "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz", - "integrity": "sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1328,13 +1328,13 @@ } }, "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.8.tgz", - "integrity": "sha512-gznWY+mr4ZQL/EWPcbBQUP3BXS5FwZp8RUOw06BaRn8tQLzN4XLIxXejpHN9Qo8x8jjBmAAKp6FoS51AgkSA/A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.9.tgz", + "integrity": "sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1344,13 +1344,13 @@ } }, "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz", - "integrity": "sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.9.tgz", + "integrity": "sha512-KRhdhlVk2nObA5AYa7QMgTMTVJdfHprfpAk4DjZVtllqRg9qarilstTKEhpVjyt+Npi8ThRyiV8176Am3CodPA==", "license": "MIT", "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1360,12 +1360,12 @@ } }, "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.8.tgz", - "integrity": "sha512-sPtYrduWINTQTW7FtOy99VCTWp4H23UX7vYcut7S4CIMEXU+54zKX9uCoGkLsWXteyaMXzVHgzWbLfQ1w4GZgw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.9.tgz", + "integrity": "sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1375,13 +1375,13 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.7.tgz", - "integrity": "sha512-q8Td2PPc6/6I73g96SreSUCKEcwMXCwcXSIAVTyTTN6CpJe0dMj8coxu1fg1T9vfBLi6Rsi6a4ECcFBbKabS5w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.9.tgz", + "integrity": "sha512-/VVukELzPDdci7UUsWQaSkhgnjIWXnIyRpM02ldxaVoFK96c41So8JcKT3m0gYjyv7j5FNPGS5vfELrWalkbDA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-flow": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-flow": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1391,13 +1391,13 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz", - "integrity": "sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.9.tgz", + "integrity": "sha512-LqHxduHoaGELJl2uhImHwRQudhCM50pT46rIBNvtT/Oql3nqiS3wOwP+5ten7NpYSXrrVLgtZU3DZmPtWZo16A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1407,14 +1407,14 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz", - "integrity": "sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", + "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1424,13 +1424,13 @@ } }, "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.8.tgz", - "integrity": "sha512-4OMNv7eHTmJ2YXs3tvxAfa/I43di+VcF+M4Wt66c88EAED1RoGaf1D64cL5FkRpNL+Vx9Hds84lksWvd/wMIdA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.9.tgz", + "integrity": "sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1440,12 +1440,12 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz", - "integrity": "sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", + "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1455,13 +1455,13 @@ } }, "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.8.tgz", - "integrity": "sha512-f5W0AhSbbI+yY6VakT04jmxdxz+WsID0neG7+kQZbCOjuyJNdL5Nn4WIBm4hRpKnUcO9lP0eipUhFN12JpoH8g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.9.tgz", + "integrity": "sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1471,13 +1471,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz", - "integrity": "sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.9.tgz", + "integrity": "sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1487,14 +1487,14 @@ } }, "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz", - "integrity": "sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.9.tgz", + "integrity": "sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1504,14 +1504,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz", - "integrity": "sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.9.tgz", + "integrity": "sha512-dwh2Ol1jWwL2MgkCzUSOvfmKElqQcuswAZypBSUsScMXvgdT8Ekq5YA6TtqpTVWH+4903NmboMuH1o9i8Rxlyg==", "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-simple-access": "^7.25.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-simple-access": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1521,16 +1521,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz", - "integrity": "sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.9.tgz", + "integrity": "sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "@babel/traverse": "^7.25.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1540,14 +1540,14 @@ } }, "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz", - "integrity": "sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.9.tgz", + "integrity": "sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-module-transforms": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-module-transforms": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1557,13 +1557,13 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz", - "integrity": "sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.9.tgz", + "integrity": "sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1573,13 +1573,13 @@ } }, "node_modules/@babel/plugin-transform-new-target": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz", - "integrity": "sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.9.tgz", + "integrity": "sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1589,13 +1589,13 @@ } }, "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.8.tgz", - "integrity": "sha512-Z7WJJWdQc8yCWgAmjI3hyC+5PXIubH9yRKzkl9ZEG647O9szl9zvmKLzpbItlijBnVhTUf1cpyWBsZ3+2wjWPQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.9.tgz", + "integrity": "sha512-ENfftpLZw5EItALAD4WsY/KUWvhUlZndm5GC7G3evUsVeSJB6p0pBeLQUnRnBCBx7zV0RKQjR9kCuwrsIrjWog==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1605,13 +1605,13 @@ } }, "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.8.tgz", - "integrity": "sha512-rm9a5iEFPS4iMIy+/A/PiS0QN0UyjPIeVvbU5EMZFKJZHt8vQnasbpo3T3EFcxzCeYO0BHfc4RqooCZc51J86Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.9.tgz", + "integrity": "sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1621,12 +1621,12 @@ } }, "node_modules/@babel/plugin-transform-object-assign": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.25.7.tgz", - "integrity": "sha512-snTWKDjknsLh7l67henNYebPZ809tYTAunlSkPHu0upP70ehLMCHnozh4Dpq7OD2e7iYxhy560iqP+FlU8c2uQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.25.9.tgz", + "integrity": "sha512-I/Vl1aQnPsrrn837oLbo+VQtkNcjuuiATqwmuweg4fTauwHHQoxyjmjjOVKyO8OaTxgqYTKW3LuQsykXjDf5Ag==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1636,14 +1636,14 @@ } }, "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.8.tgz", - "integrity": "sha512-LkUu0O2hnUKHKE7/zYOIjByMa4VRaV2CD/cdGz0AxU9we+VA3kDDggKEzI0Oz1IroG+6gUP6UmWEHBMWZU316g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.9.tgz", + "integrity": "sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==", "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-transform-parameters": "^7.25.7" + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1653,14 +1653,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz", - "integrity": "sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.9.tgz", + "integrity": "sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-replace-supers": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1670,13 +1670,13 @@ } }, "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.8.tgz", - "integrity": "sha512-EbQYweoMAHOn7iJ9GgZo14ghhb9tTjgOc88xFgYngifx7Z9u580cENCV159M4xDh3q/irbhSjZVpuhpC2gKBbg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.9.tgz", + "integrity": "sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1686,14 +1686,14 @@ } }, "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.8.tgz", - "integrity": "sha512-q05Bk7gXOxpTHoQ8RSzGSh/LHVB9JEIkKnk3myAWwZHnYiTGYtbdrYkIsS8Xyh4ltKf7GNUSgzs/6P2bJtBAQg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.9.tgz", + "integrity": "sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1703,12 +1703,12 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz", - "integrity": "sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", + "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1718,13 +1718,13 @@ } }, "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz", - "integrity": "sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", "license": "MIT", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1734,14 +1734,14 @@ } }, "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.8.tgz", - "integrity": "sha512-8Uh966svuB4V8RHHg0QJOB32QK287NBksJOByoKmHMp1TAobNniNalIkI2i5IPj5+S9NYCG4VIjbEuiSN8r+ow==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.9.tgz", + "integrity": "sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", - "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1751,13 +1751,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz", - "integrity": "sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.9.tgz", + "integrity": "sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1767,12 +1767,12 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.7.tgz", - "integrity": "sha512-r0QY7NVU8OnrwE+w2IWiRom0wwsTbjx4+xH2RTd7AVdof3uurXOF+/mXHQDRk+2jIvWgSaCHKMgggfvM4dyUGA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", + "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1782,16 +1782,16 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz", - "integrity": "sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", + "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/plugin-syntax-jsx": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1801,13 +1801,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.7.tgz", - "integrity": "sha512-5yd3lH1PWxzW6IZj+p+Y4OLQzz0/LzlOG8vGqonHfVR3euf1vyzyMUJk9Ac+m97BH46mFc/98t9PmYLyvgL3qg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.9.tgz", + "integrity": "sha512-9mj6rm7XVYs4mdLIpbZnHOYdpW42uoiBCTVowg7sP1thUOiANgMb4UtpRivR0pp5iL+ocvUv7X4mZgFRpJEzGw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.25.7" + "@babel/plugin-transform-react-jsx": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1817,12 +1817,12 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.7.tgz", - "integrity": "sha512-JD9MUnLbPL0WdVK8AWC7F7tTG2OS6u/AKKnsK+NdRhUiVdnzyR1S3kKQCaRLOiaULvUiqK6Z4JQE635VgtCFeg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", + "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1832,12 +1832,12 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.7.tgz", - "integrity": "sha512-S/JXG/KrbIY06iyJPKfxr0qRxnhNOdkNXYBl/rmwgDd72cQLH9tEGkDm/yJPGvcSIUoikzfjMios9i+xT/uv9w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", + "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1847,14 +1847,14 @@ } }, "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.7.tgz", - "integrity": "sha512-6YTHJ7yjjgYqGc8S+CbEXhLICODk0Tn92j+vNJo07HFk9t3bjFgAKxPLFhHwF2NjmQVSI1zBRfBWUeVBa2osfA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.9.tgz", + "integrity": "sha512-KQ/Takk3T8Qzj5TppkS1be588lkbTp5uj7w6a0LeQaTMSckU/wK0oJ/pih+T690tkgI5jfmg2TqDJvd41Sj1Cg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1864,12 +1864,12 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz", - "integrity": "sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.9.tgz", + "integrity": "sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-plugin-utils": "^7.25.9", "regenerator-transform": "^0.15.2" }, "engines": { @@ -1880,13 +1880,13 @@ } }, "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz", - "integrity": "sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.9.tgz", + "integrity": "sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1896,13 +1896,13 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.7.tgz", - "integrity": "sha512-Y9p487tyTzB0yDYQOtWnC+9HGOuogtP3/wNpun1xJXEEvI6vip59BSBTsHnekZLqxmPcgsrAKt46HAAb//xGhg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.25.9.tgz", + "integrity": "sha512-nZp7GlEl+yULJrClz0SwHPqir3lc0zsPrDHQUcxGspSL7AKrexNSEfTbfqnDNJUO13bgKyfuOLMF8Xqtu8j3YQ==", "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", + "@babel/helper-module-imports": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.6", "babel-plugin-polyfill-regenerator": "^0.6.1", @@ -1925,12 +1925,12 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz", - "integrity": "sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", + "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1940,13 +1940,13 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz", - "integrity": "sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", + "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1956,12 +1956,12 @@ } }, "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz", - "integrity": "sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", + "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1971,12 +1971,12 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz", - "integrity": "sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.9.tgz", + "integrity": "sha512-o97AE4syN71M/lxrCtQByzphAdlYluKPDBzDVzMmfCobUjjhAryZV0AIpRPrxN0eAkxXO6ZLEScmt+PNhj2OTw==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -1986,13 +1986,13 @@ } }, "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz", - "integrity": "sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.9.tgz", + "integrity": "sha512-v61XqUMiueJROUv66BVIOi0Fv/CUuZuZMl5NkRoCVxLAnMexZ0A3kMe7vvZ0nulxMuMp0Mk6S5hNh48yki08ZA==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2002,16 +2002,16 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.7.tgz", - "integrity": "sha512-VKlgy2vBzj8AmEzunocMun2fF06bsSWV+FvVXohtL6FGve/+L217qhHxRTVGHEDO/YR8IANcjzgJsd04J8ge5Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.9.tgz", + "integrity": "sha512-7PbZQZP50tzv2KGGnhh82GSyMB01yKY9scIjf1a+GfZCtInOWqUH5+1EBU4t9fyR5Oykkkc9vFTs4OHrhHXljQ==", "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.7", - "@babel/helper-create-class-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.7", - "@babel/plugin-syntax-typescript": "^7.25.7" + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/plugin-syntax-typescript": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2021,13 +2021,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz", - "integrity": "sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", + "integrity": "sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2037,14 +2037,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz", - "integrity": "sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.9.tgz", + "integrity": "sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2054,13 +2054,13 @@ } }, "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz", - "integrity": "sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", + "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", "license": "MIT", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2070,14 +2070,14 @@ } }, "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz", - "integrity": "sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.9.tgz", + "integrity": "sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==", "license": "MIT", "peer": true, "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7" + "@babel/helper-create-regexp-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2087,74 +2087,74 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.8.tgz", - "integrity": "sha512-58T2yulDHMN8YMUxiLq5YmWUnlDCyY1FsHM+v12VMx+1/FlrUj5tY50iDCpofFQEM8fMYOaY9YRvym2jcjn1Dg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.25.9.tgz", + "integrity": "sha512-XqDEt+hfsQukahSX9JOBDHhpUHDhj2zGSxoqWQFCMajOSBnbhBdgON/bU/5PkBA1yX5tqW6tTzuIPVsZTQ7h5Q==", "license": "MIT", "peer": true, "dependencies": { - "@babel/compat-data": "^7.25.8", - "@babel/helper-compilation-targets": "^7.25.7", - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.7", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.7", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.7", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.7", + "@babel/compat-data": "^7.25.9", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.25.9", + "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.25.9", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.25.9", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.25.9", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.25.9", "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.25.7", - "@babel/plugin-syntax-import-attributes": "^7.25.7", + "@babel/plugin-syntax-import-assertions": "^7.25.9", + "@babel/plugin-syntax-import-attributes": "^7.25.9", "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.25.7", - "@babel/plugin-transform-async-generator-functions": "^7.25.8", - "@babel/plugin-transform-async-to-generator": "^7.25.7", - "@babel/plugin-transform-block-scoped-functions": "^7.25.7", - "@babel/plugin-transform-block-scoping": "^7.25.7", - "@babel/plugin-transform-class-properties": "^7.25.7", - "@babel/plugin-transform-class-static-block": "^7.25.8", - "@babel/plugin-transform-classes": "^7.25.7", - "@babel/plugin-transform-computed-properties": "^7.25.7", - "@babel/plugin-transform-destructuring": "^7.25.7", - "@babel/plugin-transform-dotall-regex": "^7.25.7", - "@babel/plugin-transform-duplicate-keys": "^7.25.7", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.7", - "@babel/plugin-transform-dynamic-import": "^7.25.8", - "@babel/plugin-transform-exponentiation-operator": "^7.25.7", - "@babel/plugin-transform-export-namespace-from": "^7.25.8", - "@babel/plugin-transform-for-of": "^7.25.7", - "@babel/plugin-transform-function-name": "^7.25.7", - "@babel/plugin-transform-json-strings": "^7.25.8", - "@babel/plugin-transform-literals": "^7.25.7", - "@babel/plugin-transform-logical-assignment-operators": "^7.25.8", - "@babel/plugin-transform-member-expression-literals": "^7.25.7", - "@babel/plugin-transform-modules-amd": "^7.25.7", - "@babel/plugin-transform-modules-commonjs": "^7.25.7", - "@babel/plugin-transform-modules-systemjs": "^7.25.7", - "@babel/plugin-transform-modules-umd": "^7.25.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.7", - "@babel/plugin-transform-new-target": "^7.25.7", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.8", - "@babel/plugin-transform-numeric-separator": "^7.25.8", - "@babel/plugin-transform-object-rest-spread": "^7.25.8", - "@babel/plugin-transform-object-super": "^7.25.7", - "@babel/plugin-transform-optional-catch-binding": "^7.25.8", - "@babel/plugin-transform-optional-chaining": "^7.25.8", - "@babel/plugin-transform-parameters": "^7.25.7", - "@babel/plugin-transform-private-methods": "^7.25.7", - "@babel/plugin-transform-private-property-in-object": "^7.25.8", - "@babel/plugin-transform-property-literals": "^7.25.7", - "@babel/plugin-transform-regenerator": "^7.25.7", - "@babel/plugin-transform-reserved-words": "^7.25.7", - "@babel/plugin-transform-shorthand-properties": "^7.25.7", - "@babel/plugin-transform-spread": "^7.25.7", - "@babel/plugin-transform-sticky-regex": "^7.25.7", - "@babel/plugin-transform-template-literals": "^7.25.7", - "@babel/plugin-transform-typeof-symbol": "^7.25.7", - "@babel/plugin-transform-unicode-escapes": "^7.25.7", - "@babel/plugin-transform-unicode-property-regex": "^7.25.7", - "@babel/plugin-transform-unicode-regex": "^7.25.7", - "@babel/plugin-transform-unicode-sets-regex": "^7.25.7", + "@babel/plugin-transform-arrow-functions": "^7.25.9", + "@babel/plugin-transform-async-generator-functions": "^7.25.9", + "@babel/plugin-transform-async-to-generator": "^7.25.9", + "@babel/plugin-transform-block-scoped-functions": "^7.25.9", + "@babel/plugin-transform-block-scoping": "^7.25.9", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-class-static-block": "^7.25.9", + "@babel/plugin-transform-classes": "^7.25.9", + "@babel/plugin-transform-computed-properties": "^7.25.9", + "@babel/plugin-transform-destructuring": "^7.25.9", + "@babel/plugin-transform-dotall-regex": "^7.25.9", + "@babel/plugin-transform-duplicate-keys": "^7.25.9", + "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-dynamic-import": "^7.25.9", + "@babel/plugin-transform-exponentiation-operator": "^7.25.9", + "@babel/plugin-transform-export-namespace-from": "^7.25.9", + "@babel/plugin-transform-for-of": "^7.25.9", + "@babel/plugin-transform-function-name": "^7.25.9", + "@babel/plugin-transform-json-strings": "^7.25.9", + "@babel/plugin-transform-literals": "^7.25.9", + "@babel/plugin-transform-logical-assignment-operators": "^7.25.9", + "@babel/plugin-transform-member-expression-literals": "^7.25.9", + "@babel/plugin-transform-modules-amd": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-modules-systemjs": "^7.25.9", + "@babel/plugin-transform-modules-umd": "^7.25.9", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.25.9", + "@babel/plugin-transform-new-target": "^7.25.9", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.25.9", + "@babel/plugin-transform-numeric-separator": "^7.25.9", + "@babel/plugin-transform-object-rest-spread": "^7.25.9", + "@babel/plugin-transform-object-super": "^7.25.9", + "@babel/plugin-transform-optional-catch-binding": "^7.25.9", + "@babel/plugin-transform-optional-chaining": "^7.25.9", + "@babel/plugin-transform-parameters": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", + "@babel/plugin-transform-private-property-in-object": "^7.25.9", + "@babel/plugin-transform-property-literals": "^7.25.9", + "@babel/plugin-transform-regenerator": "^7.25.9", + "@babel/plugin-transform-reserved-words": "^7.25.9", + "@babel/plugin-transform-shorthand-properties": "^7.25.9", + "@babel/plugin-transform-spread": "^7.25.9", + "@babel/plugin-transform-sticky-regex": "^7.25.9", + "@babel/plugin-transform-template-literals": "^7.25.9", + "@babel/plugin-transform-typeof-symbol": "^7.25.9", + "@babel/plugin-transform-unicode-escapes": "^7.25.9", + "@babel/plugin-transform-unicode-property-regex": "^7.25.9", + "@babel/plugin-transform-unicode-regex": "^7.25.9", + "@babel/plugin-transform-unicode-sets-regex": "^7.25.9", "@babel/preset-modules": "0.1.6-no-external-plugins", "babel-plugin-polyfill-corejs2": "^0.4.10", "babel-plugin-polyfill-corejs3": "^0.10.6", @@ -2180,14 +2180,14 @@ } }, "node_modules/@babel/preset-flow": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.25.7.tgz", - "integrity": "sha512-q2x3g0YHzo/Ohsr51KOYS/BtZMsvkzVd8qEyhZAyTatYdobfgXCuyppTqTuIhdq5kR/P3nyyVvZ6H5dMc4PnCQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.25.9.tgz", + "integrity": "sha512-EASHsAhE+SSlEzJ4bzfusnXSHiU+JfAYzj+jbw2vgQKgq5HrUr8qs+vgtiEL5dOH6sEweI+PNt2D7AqrDSHyqQ==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", - "@babel/plugin-transform-flow-strip-types": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-flow-strip-types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2212,18 +2212,18 @@ } }, "node_modules/@babel/preset-react": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.7.tgz", - "integrity": "sha512-GjV0/mUEEXpi1U5ZgDprMRRgajGMRW3G5FjMr5KLKD8nT2fTG8+h/klV3+6Dm5739QE+K5+2e91qFKAYI3pmRg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.25.9.tgz", + "integrity": "sha512-D3to0uSPiWE7rBrdIICCd0tJSIGpLaaGptna2+w7Pft5xMqLpA1sz99DK5TZ1TjGbdQ/VI1eCSZ06dv3lT4JOw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", - "@babel/plugin-transform-react-display-name": "^7.25.7", - "@babel/plugin-transform-react-jsx": "^7.25.7", - "@babel/plugin-transform-react-jsx-development": "^7.25.7", - "@babel/plugin-transform-react-pure-annotations": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-transform-react-display-name": "^7.25.9", + "@babel/plugin-transform-react-jsx": "^7.25.9", + "@babel/plugin-transform-react-jsx-development": "^7.25.9", + "@babel/plugin-transform-react-pure-annotations": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2233,16 +2233,16 @@ } }, "node_modules/@babel/preset-typescript": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.25.7.tgz", - "integrity": "sha512-rkkpaXJZOFN45Fb+Gki0c+KMIglk4+zZXOoMJuyEK8y8Kkc8Jd3BDmP7qPsz0zQMJj+UD7EprF+AqAXcILnexw==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.25.9.tgz", + "integrity": "sha512-XWxw1AcKk36kgxf4C//fl0ikjLeqGUWn062/Fd8GtpTfDJOX6Ud95FK+4JlDA36BX4bNGndXi3a6Vr4Jo5/61A==", "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.25.7", - "@babel/helper-validator-option": "^7.25.7", - "@babel/plugin-syntax-jsx": "^7.25.7", - "@babel/plugin-transform-modules-commonjs": "^7.25.7", - "@babel/plugin-transform-typescript": "^7.25.7" + "@babel/helper-plugin-utils": "^7.25.9", + "@babel/helper-validator-option": "^7.25.9", + "@babel/plugin-syntax-jsx": "^7.25.9", + "@babel/plugin-transform-modules-commonjs": "^7.25.9", + "@babel/plugin-transform-typescript": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2252,9 +2252,9 @@ } }, "node_modules/@babel/register": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.7.tgz", - "integrity": "sha512-qHTd2Rhn/rKhSUwdY6+n98FmwXN+N+zxSVx3zWqRe9INyvTpv+aQ5gDV2+43ACd3VtMBzPPljbb0gZb8u5ma6Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.25.9.tgz", + "integrity": "sha512-8D43jXtGsYmEeDvm4MWHYUpWf8iiXgWYx3fW7E7Wb7Oe6FWqJPl5K6TuFW0dOwNZzEE5rjlaSJYH9JjrUKJszA==", "license": "MIT", "dependencies": { "clone-deep": "^4.0.1", @@ -2389,9 +2389,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz", - "integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.9.tgz", + "integrity": "sha512-4zpTHZ9Cm6L9L+uIqghQX8ZXg8HKFcjYO3qHoO8zTmRm6HQUJ8SSJ+KRvbMBZn0EGVlT4DRYeQ/6hjlyXBh+Kg==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -2401,30 +2401,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.7.tgz", - "integrity": "sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/types": "^7.25.7" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.7.tgz", - "integrity": "sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.9.tgz", + "integrity": "sha512-ZCuvfwOwlz/bawvAuvcj8rrithP2/N55Tzz342AkTvq4qaWbGfmCk/tKhNaV2cthijKrPAA8SRJV5WWe7IBMJw==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.25.7", - "@babel/generator": "^7.25.7", - "@babel/parser": "^7.25.7", - "@babel/template": "^7.25.7", - "@babel/types": "^7.25.7", + "@babel/code-frame": "^7.25.9", + "@babel/generator": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/template": "^7.25.9", + "@babel/types": "^7.25.9", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2442,14 +2442,13 @@ } }, "node_modules/@babel/types": { - "version": "7.25.8", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.8.tgz", - "integrity": "sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.9.tgz", + "integrity": "sha512-OwS2CM5KocvQ/k7dFJa8i5bNGJP0hXWfVCfDkqRFP1IreH1JDC7wG6eCYCi0+McbfT8OR/kNqsI0UU0xP9H6PQ==", "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.7", - "@babel/helper-validator-identifier": "^7.25.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -2794,9 +2793,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-filetypes": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.7.tgz", - "integrity": "sha512-/DN0Ujp9/EXvpTcgih9JmBaE8n+G0wtsspyNdvHT5luRfpfol1xm/CIQb6xloCXCiLkWX+EMPeLSiVIZq+24dA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.8.tgz", + "integrity": "sha512-D3N8sm/iptzfVwsib/jvpX+K/++rM8SRpLDFUaM4jxm8EyGmSIYRbKZvdIv5BkAWmMlTWoRqlLn7Yb1b11jKJg==", "dev": true, "license": "MIT" }, @@ -2864,9 +2863,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-html": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.9.tgz", - "integrity": "sha512-BNp7w3m910K4qIVyOBOZxHuFNbVojUY6ES8Y8r7YjYgJkm2lCuQoVwwhPjurnomJ7BPmZTb+3LLJ58XIkgF7JQ==", + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.10.tgz", + "integrity": "sha512-I9uRAcdtHbh0wEtYZlgF0TTcgH0xaw1B54G2CW+tx4vHUwlde/+JBOfIzird4+WcMv4smZOfw+qHf7puFUbI5g==", "dev": true, "license": "MIT" }, @@ -3042,9 +3041,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-typescript": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.10.tgz", - "integrity": "sha512-7Zek3w4Rh3ZYyhihJ34FdnUBwP3OmRldnEq3hZ+FgQ0PyYZjXv5ztEViRBBxXjiFx1nHozr6pLi74TxToD8xsg==", + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.1.11.tgz", + "integrity": "sha512-FwvK5sKbwrVpdw0e9+1lVTl8FPoHYvfHRuQRQz2Ql5XkC0gwPPkpoyD1zYImjIyZRoYXk3yp9j8ss4iz7A7zoQ==", "dev": true, "license": "MIT" }, @@ -5430,32 +5429,18 @@ "license": "MIT" }, "node_modules/@libp2p/bootstrap": { - "version": "11.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/bootstrap/-/bootstrap-11.0.8.tgz", - "integrity": "sha512-eqcXQjfaoDEYAlTpe6sGFbPOe702D7ic6pYaVkGoJFW7hCMOrhX/pvSXSc9TQz1jrtH5ue31JokiblWJ1QNtag==", + "version": "11.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/bootstrap/-/bootstrap-11.0.9.tgz", + "integrity": "sha512-0c//fq1LkYW/2CFxXTz0Z8/hisGl38Zk7LaYePJe41E6F69Bh0akDvG7rAVPGwTutw3rv0Pj2W2MsSl8woZAyA==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/interface": "^2.1.3", - "@libp2p/interface-internal": "^2.0.8", - "@libp2p/peer-id": "^5.0.5", + "@libp2p/interface-internal": "^2.0.9", + "@libp2p/peer-id": "^5.0.6", "@multiformats/mafmt": "^12.1.6", "@multiformats/multiaddr": "^12.2.3" } }, - "node_modules/@libp2p/bootstrap/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/crypto": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-5.0.5.tgz", @@ -5472,32 +5457,18 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/crypto/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/identify": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/identify/-/identify-3.0.8.tgz", - "integrity": "sha512-dQF+Cc2m1uX4YTlI9IPB8tMwvpWOWcFVl265JNYtuPJrU+VcprJKkSewd4g5jzPpb7wdVLoDQkzplQfbQmdHeQ==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/identify/-/identify-3.0.9.tgz", + "integrity": "sha512-VJjYDoOmgjw0i6xIMQxeG4B+ejzhTXkvSQ1orAhjm/aPlX542kcgAQmR9ZXiPT9OYROliNe6i4bS1MepDkO6sg==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/crypto": "^5.0.5", "@libp2p/interface": "^2.1.3", - "@libp2p/interface-internal": "^2.0.8", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/peer-record": "^8.0.8", - "@libp2p/utils": "^6.1.1", + "@libp2p/interface-internal": "^2.0.9", + "@libp2p/peer-id": "^5.0.6", + "@libp2p/peer-record": "^8.0.9", + "@libp2p/utils": "^6.1.2", "@multiformats/multiaddr": "^12.2.3", "@multiformats/multiaddr-matcher": "^1.2.1", "it-drain": "^3.0.7", @@ -5509,7 +5480,7 @@ "wherearewe": "^2.0.1" } }, - "node_modules/@libp2p/identify/node_modules/@libp2p/interface": { + "node_modules/@libp2p/interface": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", @@ -5523,34 +5494,20 @@ "uint8arraylist": "^2.4.8" } }, - "node_modules/@libp2p/interface": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.0.1.tgz", - "integrity": "sha512-zDAgu+ZNiYZxVsmcvCeNCLMnGORwLMMI8w0k2YcHwolATsv2q7QG3KpakmyKjH4m7C0hT86lGgf1sgGobPssYA==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/interface-compliance-tests": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@libp2p/interface-compliance-tests/-/interface-compliance-tests-6.1.6.tgz", - "integrity": "sha512-Joxm41kLCZTYVNMW5APJkXWDR7tWL+9nFDMvxfvZTI5RoXuR5S7qLzdpTFMfsTjUBRu7ZcejT6jSfg//9lczLw==", + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/@libp2p/interface-compliance-tests/-/interface-compliance-tests-6.1.7.tgz", + "integrity": "sha512-hXX8DuJ3dBf1IzkhbdM3/PUMbRzfp/cqbd9k5Hc9QERG0XVygbTnZaZQuEL0Oeu/UtSU92ZUXbGkVn0Qxe9Q1w==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/crypto": "^5.0.5", "@libp2p/interface": "^2.1.3", - "@libp2p/interface-internal": "^2.0.8", - "@libp2p/logger": "^5.1.1", - "@libp2p/multistream-select": "^6.0.6", - "@libp2p/peer-collections": "^6.0.8", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/utils": "^6.1.1", + "@libp2p/interface-internal": "^2.0.9", + "@libp2p/logger": "^5.1.2", + "@libp2p/multistream-select": "^6.0.7", + "@libp2p/peer-collections": "^6.0.9", + "@libp2p/peer-id": "^5.0.6", + "@libp2p/utils": "^6.1.2", "@multiformats/multiaddr": "^12.2.3", "abortable-iterator": "^5.0.1", "aegir": "^44.0.1", @@ -5578,20 +5535,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/interface-compliance-tests/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/interface-compliance-tests/node_modules/p-limit": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.1.0.tgz", @@ -5620,36 +5563,22 @@ } }, "node_modules/@libp2p/interface-internal": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/interface-internal/-/interface-internal-2.0.8.tgz", - "integrity": "sha512-yWAVuygiy2XhZK2UsOfy3iA30Bi78VeJDac6cAD/FQzu3rmGy2LNYtHuz1Vze9/OL4I6cseMNTGkozTeDg8nMg==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/interface-internal/-/interface-internal-2.0.9.tgz", + "integrity": "sha512-imXoOdKvvaQJLcmkv2ffVY9CyNbktsY2cN7aGRg8Dr1t9C7c/EDhSEfWcRQkxMAVib4jy/KnyL6JZKv5gWPu3g==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/interface": "^2.1.3", - "@libp2p/peer-collections": "^6.0.8", - "@multiformats/multiaddr": "^12.2.3", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, - "node_modules/@libp2p/interface-internal/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { + "@libp2p/peer-collections": "^6.0.9", "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", "progress-events": "^1.0.0", "uint8arraylist": "^2.4.8" } }, "node_modules/@libp2p/logger": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-5.1.1.tgz", - "integrity": "sha512-+pwFFZekKQHKdSrGURKZjfAJ86soc1e4HsI0r7dJN+kHICzKFzC+x5hM5GsWCorNj3y++xshWlF/n03zyxoyJQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-5.1.2.tgz", + "integrity": "sha512-To14ikSC+fnNXO+GkZB/Vj+kOGbdGcdpHdAMxvAWjm69ILDreGUlcDVotnAKVtN2bPAHL3Z0XzqDyKeRI6j73A==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/interface": "^2.1.3", @@ -5659,28 +5588,14 @@ "weald": "^1.0.2" } }, - "node_modules/@libp2p/logger/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/mplex": { - "version": "11.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/mplex/-/mplex-11.0.8.tgz", - "integrity": "sha512-JQ+o1Hqc/2H6dlwPwwTmXR7qRwjG90C+avTZ0X24GU25j3zEx/LQ6kb5jN2VH+KNCdq9++z5U6aHLtz2fxShFQ==", + "version": "11.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/mplex/-/mplex-11.0.9.tgz", + "integrity": "sha512-cqHY47Uq/ksoTyv1zEwoZoAaT+nfhYA0EUm1jhlYDxLDP5z/OmMEbJaJgS1LQXa55p5CKNWbGAajltWiryKzSw==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/interface": "^2.1.3", - "@libp2p/utils": "^6.1.1", + "@libp2p/utils": "^6.1.2", "it-pipe": "^3.0.1", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.1", @@ -5689,24 +5604,10 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/mplex/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/multistream-select": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@libp2p/multistream-select/-/multistream-select-6.0.6.tgz", - "integrity": "sha512-NM6CmJZYOJcB5woggoZgpMEqW6Jeovd65PYKqgvYUr7CQMPWUczUQQ9I/NSUEnv9g+69Pk9HN2AoMq1XKD60MQ==", + "version": "6.0.7", + "resolved": "https://registry.npmjs.org/@libp2p/multistream-select/-/multistream-select-6.0.7.tgz", + "integrity": "sha512-37CE4aKUlETR6FT/9yb3DXp0xMLSsz2k0Qh061IPO2WZDswwjcU8qm/ADWqEtwsvOldfoAF7pTH4FaXktC5cEw==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/interface": "^2.1.3", @@ -5720,50 +5621,22 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/multistream-select/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/peer-collections": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/peer-collections/-/peer-collections-6.0.8.tgz", - "integrity": "sha512-/xaSvb45lydLibt7sb+Im1ohIGiMfOlz5wcxelEgxmvUd0QmvirZXM3eAavQ+xrxmvJSPEQDmWSP+851ohRlKQ==", + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/peer-collections/-/peer-collections-6.0.9.tgz", + "integrity": "sha512-SQ83XUrxPoBdIezCntbXlhNxeNEqBfu/JznquoKFLVCfoTQm0251F1tApys3liGX4l1VJaLGLhLNd6dAmDRTyQ==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/interface": "^2.1.3", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/utils": "^6.1.1", + "@libp2p/peer-id": "^5.0.6", + "@libp2p/utils": "^6.1.2", "multiformats": "^13.2.2" } }, - "node_modules/@libp2p/peer-collections/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/peer-id": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-5.0.5.tgz", - "integrity": "sha512-+9aX4II0hjMgKcFX/TMWUHRu2wOXOkfV5jO2N5m/R91K+Kp4Tt4n1ceXHjrbwwz3k2IWl0xJOMYjrf9dhOZWAw==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-5.0.6.tgz", + "integrity": "sha512-gWzWm/z9dsCxL9TiOPd4VmS0V3GKMSvPWGLuNEvSA2j8+aqTzZ7jjQrF/SJtAJygD0h5jxvUnC1q05YaQUsTNA==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/crypto": "^5.0.5", @@ -5772,30 +5645,16 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/peer-id/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/peer-record": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/peer-record/-/peer-record-8.0.8.tgz", - "integrity": "sha512-wYqVN13ZaC/cVdFaTR3+Plzv4lf/BNVSzZK11cSSo3MqinOWqFs38plw9OC1Mfne2x9HYHLGwhj2zE802itD0A==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/peer-record/-/peer-record-8.0.9.tgz", + "integrity": "sha512-Ixiha//G7oCzQXSXHyXhv4Xp4qzVGSZLKUWmgUuLpqnlHrVXcqPLmPx0vkOik3ndIGriYGj5Hi7zAfCG0BN4oQ==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/crypto": "^5.0.5", "@libp2p/interface": "^2.1.3", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/utils": "^6.1.1", + "@libp2p/peer-id": "^5.0.6", + "@libp2p/utils": "^6.1.2", "@multiformats/multiaddr": "^12.2.3", "multiformats": "^13.2.2", "protons-runtime": "^5.4.0", @@ -5804,31 +5663,17 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/peer-record/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/peer-store": { - "version": "11.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/peer-store/-/peer-store-11.0.8.tgz", - "integrity": "sha512-csn1LcnnyanDw2/WO25CqxZyEzkQyfSsYu2Letsc2Po4J/9qJk8lfRc/2ezggaDf8z1y2y25b/WWhil1E7aLVA==", + "version": "11.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/peer-store/-/peer-store-11.0.9.tgz", + "integrity": "sha512-gBuSXihGtxD2r/KylgcaVm0fv0hy30j74mWcmMokpwqwLH2aLReGN9QelubmXtH2cnaRafD66QutuHNORIgRlg==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/crypto": "^5.0.5", "@libp2p/interface": "^2.1.3", - "@libp2p/peer-collections": "^6.0.8", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/peer-record": "^8.0.8", + "@libp2p/peer-collections": "^6.0.9", + "@libp2p/peer-id": "^5.0.6", + "@libp2p/peer-record": "^8.0.9", "@multiformats/multiaddr": "^12.2.3", "interface-datastore": "^8.3.0", "it-all": "^3.0.6", @@ -5839,20 +5684,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/peer-store/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/ping": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@libp2p/ping/-/ping-2.0.1.tgz", @@ -5869,17 +5700,17 @@ } }, "node_modules/@libp2p/pubsub": { - "version": "10.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/pubsub/-/pubsub-10.0.8.tgz", - "integrity": "sha512-kOAQ2I6WUDtt1H6NMQuS+bfmj/JSMeLVIjPArn7xOe6OKaiIggGFP1LEI3waKeGVzwu0HGzIoNVe7WlNuyhwmg==", + "version": "10.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/pubsub/-/pubsub-10.0.9.tgz", + "integrity": "sha512-8f6anvHz2BT3jvMrbkb3P1jlYluk6/0CiBM+9dO9JgItdANmF3uJk7FxZjOTmJAipxxnd7Gglno47AA3xnEEng==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/crypto": "^5.0.5", "@libp2p/interface": "^2.1.3", - "@libp2p/interface-internal": "^2.0.8", - "@libp2p/peer-collections": "^6.0.8", - "@libp2p/peer-id": "^5.0.5", - "@libp2p/utils": "^6.1.1", + "@libp2p/interface-internal": "^2.0.9", + "@libp2p/peer-collections": "^6.0.9", + "@libp2p/peer-id": "^5.0.6", + "@libp2p/utils": "^6.1.2", "it-length-prefixed": "^9.0.4", "it-pipe": "^3.0.1", "it-pushable": "^3.2.3", @@ -5889,30 +5720,16 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/pubsub/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/utils": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@libp2p/utils/-/utils-6.1.1.tgz", - "integrity": "sha512-lpqNyyTx7ygIfXyU4eqDONW7c4oc8Gf1xjDahlOWcggqNhLWsC3/8zTmziKlY3PjTvzY0W37nDRPO1KiM1Sduw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@libp2p/utils/-/utils-6.1.2.tgz", + "integrity": "sha512-zjzjcLz2UlX29I5xM8dJ+7IEYJ6zE91RMYf2O4lLKQue/JYUjtCyPdlX6lDG7KhgDyoyB+buN6PVutWlFQteLg==", "license": "Apache-2.0 OR MIT", "dependencies": { "@chainsafe/is-ip": "^2.0.2", "@libp2p/crypto": "^5.0.5", "@libp2p/interface": "^2.1.3", - "@libp2p/logger": "^5.1.1", + "@libp2p/logger": "^5.1.2", "@multiformats/multiaddr": "^12.2.3", "@sindresorhus/fnv1a": "^3.1.0", "@types/murmurhash3js-revisited": "^3.0.3", @@ -5933,28 +5750,14 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/@libp2p/utils/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/websockets": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@libp2p/websockets/-/websockets-9.0.8.tgz", - "integrity": "sha512-kqvdoeCGqdMjhekTeUCbzAhhrLw+cSI6bD1GdW/MOK5c5MffZ63MTZW+dT5PIVB3MviwVTRP1ogHS1X5UqMwUA==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/@libp2p/websockets/-/websockets-9.0.9.tgz", + "integrity": "sha512-8Y3WR80H3mBTkHrVqrP7CqHjiCPEH2ZThHkHq6OY/BhT7CcISWl9mtTcfalQ92JSnMP4VgHd/IwAzSPlFXVe2g==", "license": "Apache-2.0 OR MIT", "dependencies": { "@libp2p/interface": "^2.1.3", - "@libp2p/utils": "^6.1.1", + "@libp2p/utils": "^6.1.2", "@multiformats/mafmt": "^12.1.6", "@multiformats/multiaddr": "^12.2.3", "@multiformats/multiaddr-to-uri": "^10.0.1", @@ -5967,20 +5770,6 @@ "ws": "^8.17.0" } }, - "node_modules/@libp2p/websockets/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/@libp2p/websockets/node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", @@ -6171,7 +5960,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", - "dev": true, "license": "ISC", "dependencies": { "semver": "^7.3.5" @@ -8476,9 +8264,9 @@ } }, "node_modules/@rnx-kit/chromium-edge-launcher/node_modules/@types/node": { - "version": "18.19.57", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.57.tgz", - "integrity": "sha512-I2ioBd/IPrYDMv9UNR5NlPElOZ68QB7yY5V2EsLtSrTO0LM0PnCEFF9biLWHf5k+sIy4ohueCV9t4gk1AEdlVA==", + "version": "18.19.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.59.tgz", + "integrity": "sha512-vizm2EqwV/7Zay+A6J3tGl9Lhr7CjZe2HmWS988sefiEmsyP9CeXEleho6i4hJk/8UtZAo0bWN4QPZZr83RxvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8634,15 +8422,15 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.2.tgz", - "integrity": "sha512-/FIdS3PyZ39bjZlwqFnWqCOVnW7o963LtKMwQOD0NhQqw22gSr2YY1afu3FxRip4ZCZNsD5jq6Aaz6QV3D/Njw==", + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.3.tgz", + "integrity": "sha512-Pnsb6f32CD2W3uCaLZIzDmeFyQ2b8UWMFI7xtwUezpcGBDVDW6y9XgAWIlARiGAo6eNF5FK5aQTr0LFyNyqq5A==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" + "picomatch": "^4.0.2" }, "engines": { "node": ">=14.0.0" @@ -8656,6 +8444,19 @@ } } }, + "node_modules/@rollup/pluginutils/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", @@ -9999,9 +9800,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "22.7.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.7.tgz", - "integrity": "sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q==", + "version": "22.7.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.7.9.tgz", + "integrity": "sha512-jrTfRC7FM6nChvU7X2KqcrgquofrWLFDeYC1hKfwNWomVvrn7JIksqf344WN2X/y8xrgqBd2dJATZV4GbatBfg==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -10095,9 +9896,9 @@ } }, "node_modules/@types/ssh2/node_modules/@types/node": { - "version": "18.19.57", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.57.tgz", - "integrity": "sha512-I2ioBd/IPrYDMv9UNR5NlPElOZ68QB7yY5V2EsLtSrTO0LM0PnCEFF9biLWHf5k+sIy4ohueCV9t4gk1AEdlVA==", + "version": "18.19.59", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.59.tgz", + "integrity": "sha512-vizm2EqwV/7Zay+A6J3tGl9Lhr7CjZe2HmWS988sefiEmsyP9CeXEleho6i4hJk/8UtZAo0bWN4QPZZr83RxvQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11093,9 +10894,9 @@ } }, "node_modules/aegir/node_modules/@types/node": { - "version": "20.16.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.13.tgz", - "integrity": "sha512-GjQ7im10B0labo8ZGXDGROUl9k0BNyDgzfGpb4g/cl+4yYDWVKcozANF4FGr4/p0O/rAkQClM6Wiwkije++1Tg==", + "version": "20.17.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.0.tgz", + "integrity": "sha512-a7zRo0f0eLo9K5X9Wp5cAqTUNGzuFLDG2R7C4HY2BhcMAsxgSPuRvAC1ZB6QkuUQXf0YZAgfOX2ZyrBa2n4nHQ==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -11581,9 +11382,9 @@ } }, "node_modules/allure-commandline": { - "version": "2.30.0", - "resolved": "https://registry.npmjs.org/allure-commandline/-/allure-commandline-2.30.0.tgz", - "integrity": "sha512-qSaGG/I8P38q8gufnxvEog+IrIeCick+PJxxoTp5Vh/L8kviymIfv3A7fvYWziOqZ/oDywyOuNFMEfPZiiKwAA==", + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/allure-commandline/-/allure-commandline-2.31.0.tgz", + "integrity": "sha512-/gwfIeMlz030fK8ZML/jSEzTtXsSRnsdx9ppfXR0jHvG+cO0pI/wZhq7YoMYgGEL8iVURIY2lDJlDyzOfHeSkw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -12218,15 +12019,6 @@ "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", - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -12463,9 +12255,9 @@ } }, "node_modules/bare-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.1.tgz", - "integrity": "sha512-Vm8kAeOcfzHPTH8sq0tHBnUqYrkXdroaBVVylqFT4cF5wnMfKEIxxy2jIGu2zKVNl9P8MAP9XBWwXJ9N2+jfEw==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.2.tgz", + "integrity": "sha512-EFZHSIBkDgSHIwj2l2QZfP4U5OcD4xFAOwhSb/vlr9PIqyGJGvB/nfClJbcnh3EY4jtPE4zsb5ztae96bVF79A==", "dev": true, "license": "Apache-2.0", "optional": true, @@ -12841,9 +12633,9 @@ "license": "ISC" }, "node_modules/browserslist": { - "version": "4.24.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", - "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "funding": [ { "type": "opencollective", @@ -12860,10 +12652,10 @@ ], "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001663", - "electron-to-chromium": "^1.5.28", + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", "node-releases": "^2.0.18", - "update-browserslist-db": "^1.1.0" + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -13040,7 +12832,6 @@ "version": "18.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", - "dev": true, "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", @@ -13064,7 +12855,6 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -13085,14 +12875,12 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, "license": "ISC" }, "node_modules/cacache/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -13108,7 +12896,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" @@ -13546,7 +13333,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -16132,9 +15918,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.41", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz", - "integrity": "sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ==", + "version": "1.5.44", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.44.tgz", + "integrity": "sha512-Lz3POUa7wANQA8G+9btKAdH+cqkfWCBdkotvQZJVOqRXMYGm1tTD835Z01iCjWpEBf0RInPBWuPfzhGbxOCULw==", "license": "ISC" }, "node_modules/electron-window": { @@ -18738,7 +18524,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -19596,7 +19381,6 @@ "version": "3.0.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", - "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -19609,7 +19393,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -19888,7 +19671,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", - "dev": true, "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -22339,20 +22121,6 @@ "uint8arrays": "^5.1.0" } }, - "node_modules/libp2p/node_modules/@libp2p/interface": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.1.3.tgz", - "integrity": "sha512-t1i2LWcnTGJEr7fDMslA8wYwBzJP81QKBlrBHoGhXxqqpRQa9035roCh/Akuw5RUgjKE47/ezjuzo90aWsJB8g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.2.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.1", - "multiformats": "^13.1.0", - "progress-events": "^1.0.0", - "uint8arraylist": "^2.4.8" - } - }, "node_modules/lighthouse-logger": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", @@ -23791,9 +23559,9 @@ } }, "node_modules/markdown-table": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", - "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", "license": "MIT", "funding": { "type": "github", @@ -25552,7 +25320,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -25565,7 +25332,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -25578,7 +25344,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -25591,7 +25356,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -25604,7 +25368,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -25617,7 +25380,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -25631,7 +25393,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -26079,9 +25840,9 @@ } }, "node_modules/nise/node_modules/@sinonjs/fake-timers": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.3.tgz", - "integrity": "sha512-golm/Sc4CqLV/ZalIP14Nre7zPgd8xG/S3nHULMTBHMX0llyTNhE1O6nrgbfvLX2o0y849CnLKdu8OE05Ztiiw==", + "version": "13.0.4", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.4.tgz", + "integrity": "sha512-wpUq+QiKxrWk7U2pdvNSY9fNX62/k+7eEdlQMO0A3rU8tQ+vvzY/WzBhMz+GbQlATXZlXWYQqFWNFcn1SVvThA==", "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.1" @@ -26475,7 +26236,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz", "integrity": "sha512-xXxr8y5U0kl8dVkz2oK7yZjPBvqM2fwaO5l3Yg13p03v8+E3qQcD0JNhHzjL1vyGgxcKkD0cco+NLR72iuPk3g==", - "dev": true, "license": "ISC", "dependencies": { "hosted-git-info": "^3.0.2", @@ -26488,14 +26248,12 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "dev": true, "license": "MIT" }, "node_modules/npm-package-arg/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -26505,7 +26263,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", - "dev": true, "license": "ISC", "dependencies": { "builtins": "^1.0.3" @@ -30535,7 +30292,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -30555,7 +30311,6 @@ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "deprecated": "This package is no longer supported.", - "dev": true, "license": "ISC", "dependencies": { "os-homedir": "^1.0.0", @@ -33310,7 +33065,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", - "dev": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" } @@ -36844,7 +36598,6 @@ "version": "10.0.6", "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -37560,7 +37313,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dev": true, "license": "ISC", "dependencies": { "chownr": "^2.0.0", @@ -37605,7 +37357,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -37618,7 +37369,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -37631,7 +37381,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, "license": "ISC", "engines": { "node": ">=8" @@ -37641,7 +37390,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -38084,15 +37832,6 @@ "license": "BSD-3-Clause", "peer": true }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -38966,7 +38705,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "dev": true, "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" @@ -38979,7 +38717,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" @@ -40221,9 +39958,9 @@ "version": "0.0.33", "license": "MIT OR Apache-2.0", "dependencies": { - "@libp2p/ping": "^1.1.2", - "@waku/enr": "^0.0.26", - "@waku/interfaces": "0.0.27", + "@libp2p/ping": "2.0.1", + "@waku/enr": "^0.0.27", + "@waku/interfaces": "0.0.28", "@waku/proto": "0.0.8", "@waku/utils": "0.0.21", "debug": "^4.3.4", @@ -40329,6 +40066,8 @@ }, "packages/discovery/node_modules/@libp2p/peer-id": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-5.0.1.tgz", + "integrity": "sha512-HwoW7dQ/o4NQ+5PQThOzMK2OHMRicmTZxVuMjbjWcPNnNWb8x/5vwjzdEUfqXimHYdZTIpy2PMMq6Jf4zvculQ==", "dev": true, "license": "Apache-2.0 OR MIT", "dependencies": { @@ -40559,7 +40298,6 @@ "@waku/message-hash": "0.1.17", "@waku/proto": "^0.0.8", "@waku/utils": "0.0.21", - "async-mutex": "^0.5.0", "libp2p": "2.1.8" }, "devDependencies": { diff --git a/packages/tests/tests/filter/peer_management.spec.ts b/packages/tests/tests/filter/peer_management.spec.ts deleted file mode 100644 index 7f3525ca38..0000000000 --- a/packages/tests/tests/filter/peer_management.spec.ts +++ /dev/null @@ -1,323 +0,0 @@ -import { ISubscription, LightNode, SDKProtocolResult } from "@waku/interfaces"; -import { - createDecoder, - createEncoder, - DecodedMessage, - utf8ToBytes -} from "@waku/sdk"; -import { delay } from "@waku/utils"; -import { expect } from "chai"; -import { describe } from "mocha"; - -import { - afterEachCustom, - beforeEachCustom, - DefaultTestPubsubTopic, - DefaultTestShardInfo, - runMultipleNodes, - ServiceNode, - ServiceNodesFleet, - teardownNodesWithRedundancy -} from "../../src/index.js"; - -describe("Waku Filter: Peer Management: E2E", function () { - this.timeout(15000); - let waku: LightNode; - let serviceNodes: ServiceNodesFleet; - - const contentTopic = "/test"; - - const encoder = createEncoder({ - pubsubTopic: DefaultTestPubsubTopic, - contentTopic - }); - - const decoder = createDecoder(contentTopic, DefaultTestPubsubTopic); - - beforeEachCustom(this, async () => { - [serviceNodes, waku] = await runMultipleNodes( - this.ctx, - DefaultTestShardInfo, - { lightpush: true, filter: true }, - undefined, - 5 - ); - }); - - afterEachCustom(this, async () => { - await teardownNodesWithRedundancy(serviceNodes, waku); - }); - - it("Number of peers are maintained correctly", async function () { - const messages: DecodedMessage[] = []; - const { error, results } = await waku.filter.subscribe([decoder], (msg) => { - messages.push(msg); - }); - - if (error) { - throw error; - } - - const { successes, failures } = results; - - await waku.lightPush.send(encoder, { - payload: utf8ToBytes("Hello_World") - }); - - expect(successes.length).to.be.greaterThan(0); - expect(successes.length).to.be.equal(waku.filter.numPeersToUse); - - if (failures) { - expect(failures.length).to.equal(0); - } - }); - - it("Ping succeeds for all connected peers", async function () { - const { error, subscription } = await waku.filter.subscribe( - [decoder], - () => {} - ); - if (error) { - throw error; - } - const pingResult = await subscription.ping(); - expect(pingResult.successes.length).to.equal(waku.filter.numPeersToUse); - expect(pingResult.failures.length).to.equal(0); - }); - - it("Ping fails for unsubscribed peers", async function () { - const { error, subscription } = await waku.filter.subscribe( - [decoder], - () => {} - ); - if (error) { - throw error; - } - await subscription.unsubscribe([contentTopic]); - const pingResult = await subscription.ping(); - expect(pingResult.successes.length).to.equal(0); - expect(pingResult.failures.length).to.be.greaterThan(0); - }); - - it("Keep-alive pings maintain the connection", async function () { - const { error, subscription } = await waku.filter.subscribe( - [decoder], - () => {}, - undefined, - { keepAlive: 100 } - ); - if (error) { - throw error; - } - - await delay(1000); - - const pingResult = await subscription.ping(); - expect(pingResult.successes.length).to.equal(waku.filter.numPeersToUse); - expect(pingResult.failures.length).to.equal(0); - }); - - it("Renews peer on consistent ping failures", async function () { - const maxPingFailures = 3; - const { error, subscription } = await waku.filter.subscribe( - [decoder], - () => {}, - undefined, - { - pingsBeforePeerRenewed: maxPingFailures - } - ); - if (error) { - throw error; - } - - const disconnectedNodePeerId = waku.filter.connectedPeers[0].id; - await waku.connectionManager.dropConnection(disconnectedNodePeerId); - - // Ping multiple times to exceed max failures - for (let i = 0; i <= maxPingFailures; i++) { - await subscription.ping(); - await delay(100); - } - - const pingResult = await subscription.ping(); - expect(pingResult.successes.length).to.equal(waku.filter.numPeersToUse); - expect(pingResult.failures.length).to.equal(0); - - expect(waku.filter.connectedPeers.length).to.equal( - waku.filter.numPeersToUse - ); - expect( - waku.filter.connectedPeers.some((peer) => - peer.id.equals(disconnectedNodePeerId) - ) - ).to.eq(false); - }); - - it("Tracks peer failures correctly", async function () { - const maxPingFailures = 3; - const { error, subscription } = await waku.filter.subscribe( - [decoder], - () => {}, - undefined, - { - pingsBeforePeerRenewed: maxPingFailures - } - ); - if (error) { - throw error; - } - - const targetPeer = waku.filter.connectedPeers[0]; - await waku.connectionManager.dropConnection(targetPeer.id); - - for (let i = 0; i < maxPingFailures; i++) { - await subscription.ping(targetPeer.id); - } - - // At this point, the peer should not be renewed yet - expect( - waku.filter.connectedPeers.some((peer) => peer.id.equals(targetPeer.id)) - ).to.be.true; - - // One more failure should trigger renewal - await subscription.ping(targetPeer.id); - - // adds delay as renewal happens as an async operation in the bg - await delay(300); - - expect( - waku.filter.connectedPeers.some((peer) => peer.id.equals(targetPeer.id)) - ).to.eq(false); - expect(waku.filter.connectedPeers.length).to.equal( - waku.filter.numPeersToUse - ); - }); - - it("Maintains correct number of peers after multiple subscribe/unsubscribe cycles", async function () { - let subscription: ISubscription; - for (let i = 0; i < 3; i++) { - const { error, subscription: _subscription } = - await waku.filter.subscribe([decoder], () => {}); - if (error) { - throw error; - } - subscription = _subscription; - let pingResult = await subscription.ping(); - expect(pingResult.successes.length).to.equal(waku.filter.numPeersToUse); - - await subscription.unsubscribe([contentTopic]); - pingResult = await subscription.ping(); - expect(pingResult.failures.length).to.be.greaterThan(0); - await subscription.subscribe([decoder], () => {}); - } - - const finalPingResult = await subscription!.ping(); - expect(finalPingResult.successes.length).to.equal( - waku.filter.numPeersToUse - ); - }); - - it("Renews peer on consistent missed messages", async function () { - const [serviceNodes, waku] = await runMultipleNodes( - this.ctx, - DefaultTestShardInfo, - { lightpush: true, filter: true }, - undefined, - 2 - ); - const serviceNodesPeerIdStr = await Promise.all( - serviceNodes.nodes.map(async (node) => - (await node.getPeerId()).toString() - ) - ); - const nodeWithoutDiscovery = new ServiceNode("WithoutDiscovery"); - await nodeWithoutDiscovery.start({ lightpush: true, filter: true }); - const nodeWithouDiscoveryPeerIdStr = ( - await nodeWithoutDiscovery.getPeerId() - ).toString(); - await waku.dial(await nodeWithoutDiscovery.getMultiaddrWithId()); - - const messages: DecodedMessage[] = []; - const { error, results } = await waku.filter.subscribe([decoder], (msg) => { - messages.push(msg); - }); - if (error) { - throw error; - } - - const { successes } = results; - - expect(successes.length).to.be.greaterThan(0); - expect(successes.length).to.be.equal(waku.filter.numPeersToUse); - - const sendMessage: () => Promise = async () => - waku.lightPush.send(encoder, { - payload: utf8ToBytes("Hello_World") - }); - - await sendMessage(); - - successes - .map((peerId) => - [nodeWithouDiscoveryPeerIdStr, ...serviceNodesPeerIdStr].includes( - peerId.toString() - ) - ) - .forEach((isConnected) => expect(isConnected).to.eq(true)); - - // send 2 more messages - await sendMessage(); - await sendMessage(); - - expect(waku.filter.connectedPeers.length).to.equal(2); - }); - - it("Renews peer for Filter on peer:disconnect event", async function () { - this.timeout(30000); - - const messages: DecodedMessage[] = []; - const { error, subscription } = await waku.filter.subscribe( - [decoder], - (msg) => { - messages.push(msg); - } - ); - - if (error) { - throw error; - } - - const initialPeers = waku.filter.connectedPeers; - expect(initialPeers.length).to.equal(waku.filter.numPeersToUse); - - const peerToDisconnect = initialPeers[0]; - await waku.connectionManager.dropConnection(peerToDisconnect.id); - - await delay(5000); - - expect(waku.filter.connectedPeers.length).to.equal( - waku.filter.numPeersToUse - ); - - const stillConnected = waku.filter.connectedPeers.some((peer) => - peer.id.equals(peerToDisconnect.id) - ); - expect(stillConnected).to.be.false; - - await waku.lightPush.send(encoder, { - payload: utf8ToBytes("Hello after disconnect") - }); - - await delay(2000); - - expect(messages.length).to.equal(1); - expect(new TextDecoder().decode(messages[0].payload)).to.equal( - "Hello after disconnect" - ); - - const pingResult = await subscription.ping(); - expect(pingResult.successes.length).to.equal(waku.filter.numPeersToUse); - expect(pingResult.failures.length).to.equal(0); - }); -}); From 8a3337df8916da3f745bcf9e789ffa7104be48a5 Mon Sep 17 00:00:00 2001 From: Sasha Date: Thu, 24 Oct 2024 17:47:44 +0200 Subject: [PATCH 11/12] update deps and lock --- package-lock.json | 37 ++++++++++++++++++++++++++++++++- packages/core/package.json | 1 + packages/discovery/package.json | 2 +- packages/sdk/package.json | 1 + 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 518f07b4c2..6126151686 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5960,6 +5960,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", + "dev": true, "license": "ISC", "dependencies": { "semver": "^7.3.5" @@ -12832,6 +12833,7 @@ "version": "18.0.4", "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.4.tgz", "integrity": "sha512-B+L5iIa9mgcjLbliir2th36yEwPftrzteHYujzsx3dFP/31GCHcIeS8f5MGd80odLOjaOvSpU3EEAmRQptkxLQ==", + "dev": true, "license": "ISC", "dependencies": { "@npmcli/fs": "^3.1.0", @@ -12855,6 +12857,7 @@ "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -12875,12 +12878,14 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, "license": "ISC" }, "node_modules/cacache/node_modules/minimatch": { "version": "9.0.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -12896,6 +12901,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" @@ -13333,6 +13339,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -18524,6 +18531,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -19381,6 +19389,7 @@ "version": "3.0.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, "license": "ISC", "dependencies": { "lru-cache": "^6.0.0" @@ -19393,6 +19402,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -19671,6 +19681,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" @@ -25320,6 +25331,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -25332,6 +25344,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -25344,6 +25357,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -25356,6 +25370,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -25368,6 +25383,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -25380,6 +25396,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, "license": "MIT", "dependencies": { "minipass": "^3.0.0", @@ -25393,6 +25410,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -26236,6 +26254,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-7.0.0.tgz", "integrity": "sha512-xXxr8y5U0kl8dVkz2oK7yZjPBvqM2fwaO5l3Yg13p03v8+E3qQcD0JNhHzjL1vyGgxcKkD0cco+NLR72iuPk3g==", + "dev": true, "license": "ISC", "dependencies": { "hosted-git-info": "^3.0.2", @@ -26248,12 +26267,14 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", + "dev": true, "license": "MIT" }, "node_modules/npm-package-arg/node_modules/semver": { "version": "5.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver" @@ -26263,6 +26284,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "dev": true, "license": "ISC", "dependencies": { "builtins": "^1.0.3" @@ -30292,6 +30314,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -30311,6 +30334,7 @@ "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", "deprecated": "This package is no longer supported.", + "dev": true, "license": "ISC", "dependencies": { "os-homedir": "^1.0.0", @@ -33065,6 +33089,7 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz", "integrity": "sha512-Uu7ii+FQy4Qf82G4xu7ShHhjhGahEpCWc3x8UavY3CTcWV+ufmmCtwkr7ZKsX42jdL0kr1B5FKUeqJvAn51jzQ==", + "dev": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" } @@ -36598,6 +36623,7 @@ "version": "10.0.6", "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" @@ -37313,6 +37339,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dev": true, "license": "ISC", "dependencies": { "chownr": "^2.0.0", @@ -37357,6 +37384,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, "license": "ISC", "dependencies": { "minipass": "^3.0.0" @@ -37369,6 +37397,7 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, "license": "ISC", "dependencies": { "yallist": "^4.0.0" @@ -37381,6 +37410,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, "license": "ISC", "engines": { "node": ">=8" @@ -37390,6 +37420,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" @@ -38705,6 +38736,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" @@ -38717,6 +38749,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" @@ -39971,6 +40004,7 @@ "uuid": "^9.0.0" }, "devDependencies": { + "@libp2p/interface": "^2.1.3", "@libp2p/peer-id": "^5.0.1", "@multiformats/multiaddr": "^12.0.0", "@rollup/plugin-commonjs": "^25.0.7", @@ -40056,7 +40090,7 @@ "node": ">=20" }, "peerDependencies": { - "@libp2p/interface": "2.0.1" + "@libp2p/interface": "^2.1.3" }, "peerDependenciesMeta": { "@libp2p/interface": { @@ -40301,6 +40335,7 @@ "libp2p": "2.1.8" }, "devDependencies": { + "@libp2p/interface": "2.1.3", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.2.3", diff --git a/packages/core/package.json b/packages/core/package.json index f4677fe6ae..2bc992d5b6 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -82,6 +82,7 @@ }, "devDependencies": { "@libp2p/peer-id": "^5.0.1", + "@libp2p/interface": "^2.1.3", "@multiformats/multiaddr": "^12.0.0", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-json": "^6.0.0", diff --git a/packages/discovery/package.json b/packages/discovery/package.json index d5eae3d778..e3a15698a7 100644 --- a/packages/discovery/package.json +++ b/packages/discovery/package.json @@ -80,7 +80,7 @@ "sinon": "^18.0.0" }, "peerDependencies": { - "@libp2p/interface": "2.0.1" + "@libp2p/interface": "^2.1.3" }, "peerDependenciesMeta": { "@libp2p/interface": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index 96560a06e7..1d1521cad6 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -76,6 +76,7 @@ "libp2p": "2.1.8" }, "devDependencies": { + "@libp2p/interface": "2.1.3", "@types/chai": "^4.3.11", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-json": "^6.0.0", From d4210c7d178e73840e8bf1bbd4efcb70265c350e Mon Sep 17 00:00:00 2001 From: Sasha Date: Thu, 24 Oct 2024 17:53:08 +0200 Subject: [PATCH 12/12] remove old test for peerManager, fix check and spell --- .cspell.json | 1 + .../protocols/light_push/light_push.spec.ts | 5 +- .../sdk/src/protocols/peer_manager.spec.ts | 148 ------------------ 3 files changed, 5 insertions(+), 149 deletions(-) delete mode 100644 packages/sdk/src/protocols/peer_manager.spec.ts diff --git a/.cspell.json b/.cspell.json index 99da5df60e..1b262f3a0d 100644 --- a/.cspell.json +++ b/.cspell.json @@ -116,6 +116,7 @@ "upgrader", "vacp", "varint", + "weboko", "waku", "wakuconnect", "wakunode", diff --git a/packages/sdk/src/protocols/light_push/light_push.spec.ts b/packages/sdk/src/protocols/light_push/light_push.spec.ts index 1e0a24293c..7c695212b5 100644 --- a/packages/sdk/src/protocols/light_push/light_push.spec.ts +++ b/packages/sdk/src/protocols/light_push/light_push.spec.ts @@ -10,6 +10,8 @@ import { utf8ToBytes } from "@waku/utils/bytes"; import { expect } from "chai"; import sinon from "sinon"; +import { PeerManager } from "../peer_manager.js"; + import { LightPush } from "./light_push.js"; const PUBSUB_TOPIC = "/waku/2/rs/1/4"; @@ -156,7 +158,8 @@ function mockLightPush(options: MockLightPushOptions): LightPush { return new LightPush( { configuredPubsubTopics: options.pubsubTopics || [PUBSUB_TOPIC] - } as ConnectionManager, + } as unknown as ConnectionManager, + {} as unknown as PeerManager, options.libp2p ); } diff --git a/packages/sdk/src/protocols/peer_manager.spec.ts b/packages/sdk/src/protocols/peer_manager.spec.ts deleted file mode 100644 index bea3bb0c6d..0000000000 --- a/packages/sdk/src/protocols/peer_manager.spec.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { Peer, PeerId } from "@libp2p/interface"; -import { ConnectionManager, LightPushCodec } from "@waku/core"; -import { BaseProtocol } from "@waku/core/lib/base_protocol"; -import { Logger } from "@waku/utils"; -import { expect } from "chai"; -import sinon from "sinon"; - -import { PeerManager } from "./peer_manager.js"; - -describe("PeerManager", () => { - let peerManager: PeerManager; - let mockConnectionManager: sinon.SinonStubbedInstance; - let mockCore: sinon.SinonStubbedInstance; - let mockLogger: any; - - beforeEach(() => { - mockConnectionManager = sinon.createStubInstance(ConnectionManager); - mockCore = sinon.createStubInstance(BaseProtocol); - mockLogger = { - info: sinon.stub(), - warn: sinon.stub(), - error: sinon.stub(), - debug: sinon.stub(), - extend: sinon.stub().returns({ - info: sinon.stub(), - warn: sinon.stub(), - error: sinon.stub(), - debug: sinon.stub() - }) - }; - - mockCore.multicodec = LightPushCodec; - - peerManager = new PeerManager( - mockConnectionManager as any, - mockCore as any, - mockLogger as Logger - ); - }); - - afterEach(() => { - sinon.restore(); - }); - - const createMockPeer = (id: string): Peer => - ({ - id: { - toString: () => id - } as PeerId - }) as Peer; - - describe("addPeer", () => { - it("should add a peer", async () => { - const peer = createMockPeer("peer1"); - await peerManager.addPeer(peer); - - expect(mockConnectionManager.attemptDial.calledWith(peer.id)).to.be.true; - expect( - mockLogger.info.calledWith(sinon.match(/Added and dialed peer: peer1/)) - ).to.be.true; - expect(await peerManager.getPeerCount()).to.equal(1); - }); - }); - - describe("removePeer", () => { - it("should remove a peer", async () => { - const peer = createMockPeer("peer1"); - await peerManager.addPeer(peer); - await peerManager.removePeer(peer.id); - - expect(mockLogger.info.calledWith(sinon.match(/Removed peer: peer1/))).to - .be.true; - expect(await peerManager.getPeerCount()).to.equal(0); - }); - }); - - describe("getPeerCount", () => { - it("should return the correct number of peers", async () => { - await peerManager.addPeer(createMockPeer("peer1")); - await peerManager.addPeer(createMockPeer("peer2")); - - const count = await peerManager.getPeerCount(); - expect(count).to.equal(2); - }); - }); - - describe("hasPeers", () => { - it("should return true when peers exist", async () => { - await peerManager.addPeer(createMockPeer("peer1")); - const result = await peerManager.hasPeers(); - expect(result).to.be.true; - }); - - it("should return false when no peers exist", async () => { - const result = await peerManager.hasPeers(); - expect(result).to.be.false; - }); - }); - - describe("removeExcessPeers", () => { - it("should remove the specified number of excess peers", async () => { - await peerManager.addPeer(createMockPeer("peer1")); - await peerManager.addPeer(createMockPeer("peer2")); - await peerManager.addPeer(createMockPeer("peer3")); - - await peerManager.removeExcessPeers(2); - - const count = await peerManager.getPeerCount(); - expect(count).to.equal(1); - expect(mockLogger.info.calledWith(`Removing 2 excess peer(s)`)).to.be - .true; - }); - }); - - describe("findAndAddPeers", () => { - it("should find and add new peers", async () => { - const newPeers = [createMockPeer("peer1"), createMockPeer("peer2")]; - mockCore.getPeers.resolves(newPeers); - - const addedPeers = await peerManager.findAndAddPeers(2); - - expect(addedPeers).to.have.lengthOf(2); - expect(mockConnectionManager.attemptDial.callCount).to.equal(2); - }); - - it("should not add existing peers", async () => { - const existingPeer = createMockPeer("existing"); - await peerManager.addPeer(existingPeer); - - const newPeers = [existingPeer, createMockPeer("new")]; - mockCore.getPeers.resolves(newPeers); - - const addedPeers = await peerManager.findAndAddPeers(2); - - expect(addedPeers).to.have.lengthOf(1); - expect(mockConnectionManager.attemptDial.callCount).to.equal(2); // Once for existing, once for new - }); - - it("should log when no additional peers are found", async () => { - mockCore.getPeers.resolves([]); - - await peerManager.findAndAddPeers(2); - - expect(mockLogger.warn.calledWith("No additional peers found")).to.be - .true; - }); - }); -});