From bc9f99937d24d8f0026fc431465c939dfe89742f Mon Sep 17 00:00:00 2001 From: Dmytro Demchenko <91938357+DimaDemchenko@users.noreply.github.com> Date: Sun, 23 Jun 2024 15:02:30 +0300 Subject: [PATCH] Update Tracker Architecture for Multi-Peer Connections (#77) * chore: Update npm dependencies to latest versions * refactor: update tracker to support multiple peers on one connection * refactor: Remove unused code for peers in FastTracker * refactor: processStop * refactor: disconnect peer * feat: Add clearPeersInterval to automatically disconnect inactive peers * refactor: tracker announce & disconnect logic * refactor: small improvements * refactor: Update SocketContext references in heap-usage and simulation.test * refactor: Update tests * refactor: Improvements * refactor: Improve FastTracker by optimizing peer management * Remove completedCount * Refactor remove peer messages * Fix peers statistics * Fix WebSockets counter * Revert socket counter * Enable messages debugging --------- Co-authored-by: Andriy Lysnevych --- lib/fast-tracker.ts | 435 +++++++++---------- lib/index.ts | 6 +- lib/run-uws-tracker.ts | 2 +- lib/tracker.ts | 21 +- lib/uws-tracker.ts | 34 +- package-lock.json | 849 +++++++++++++++++++------------------- package.json | 22 +- test/announce.test.ts | 426 +++---------------- test/memory/heap-usage.ts | 6 +- test/simulation.test.ts | 20 +- 10 files changed, 754 insertions(+), 1067 deletions(-) diff --git a/lib/fast-tracker.ts b/lib/fast-tracker.ts index d213e8f..6bfeedc 100644 --- a/lib/fast-tracker.ts +++ b/lib/fast-tracker.ts @@ -15,7 +15,13 @@ */ import Debug from "debug"; -import { Tracker, PeerContext, TrackerError } from "./tracker.js"; +import { + Tracker, + SocketContext, + PeerContext, + TrackerError, + Swarm, +} from "./tracker.js"; const debug = Debug("wt-tracker:fast-tracker"); const debugEnabled = debug.enabled; @@ -33,19 +39,126 @@ export class FastTracker implements Tracker { readonly #swarms = new Map(); readonly #peers = new Map(); + #clearPeersInterval?: NodeJS.Timeout; + public constructor(settings?: Partial) { this.settings = { maxOffers: 20, - announceInterval: 120, + announceInterval: 20, ...settings, }; + this.startClearPeersInterval(); + } + + private getOrCreateSwarm(infoHash: string) { + let swarm = this.#swarms.get(infoHash); + + if (swarm === undefined) { + if (typeof infoHash !== "string") { + throw new TrackerError("announce: info_hash field is missing or wrong"); + } + + if (debugEnabled) { + debug( + "announce: swarm created:", + Buffer.from(infoHash).toString("hex"), + ); + } + + swarm = { + infoHash, + peers: [], + }; + + this.#swarms.set(infoHash, swarm); + } + + return swarm; + } + + private addPeerToSwarm( + swarm: Swarm, + peer: PeerContext, + isPeerCompleted: boolean, + ) { + swarm.peers.push(peer); + if (isPeerCompleted) { + if (swarm.completedPeers === undefined) { + swarm.completedPeers = new Set(); + } + swarm.completedPeers.add(peer.peerId); + } + } + + private removePeerFromSwarm(swarm: Swarm, peer: PeerContext) { + const peerIndex = swarm.peers.indexOf(peer); + + swarm.completedPeers?.delete(peer.peerId); + + const lastPeer = swarm.peers.pop()!; + if (peerIndex < swarm.peers.length) { + swarm.peers[peerIndex] = lastPeer; + } + + if (swarm.peers.length === 0) { + if (debugEnabled) { + debug( + "disconnect peer: swarm removed (empty)", + Buffer.from(swarm.infoHash).toString("hex"), + ); + } + this.#swarms.delete(swarm.infoHash); + } + } + + private setPeerCompletedInSwarm(swarm: Swarm, peer: PeerContext) { + if (swarm.completedPeers === undefined) { + swarm.completedPeers = new Set(); + } + swarm.completedPeers.add(peer.peerId); + } + + private startClearPeersInterval(): void { + if (this.#clearPeersInterval !== undefined) { + clearInterval(this.#clearPeersInterval); + this.#clearPeersInterval = undefined; + } + + this.#clearPeersInterval = setInterval(() => { + const now = performance.now(); + for (const peer of this.#peers.values()) { + if ( + now - peer.lastAccessed > + this.settings.announceInterval * 2 * 1000 + ) { + if (debugEnabled) { + debug( + "remove by timeout peer:", + Buffer.from(peer.peerId).toString("hex"), + "swarm:", + Buffer.from(peer.swarm.infoHash).toString("hex"), + ); + } + this.removePeer(peer); + } + } + }, this.settings.announceInterval * 1000); + } + + private removePeer(peer: PeerContext) { + const swarm = peer.swarm; + + this.removePeerFromSwarm(swarm, peer); + this.#peers.delete(peer.peerId); + + delete (peer.socket as unknown as UnknownObject)[peer.peerId]; } public get swarms(): ReadonlyMap { return this.#swarms; } - public processMessage(jsonObject: object, peer: PeerContext): void { + public processMessage(jsonObject: object, peer: SocketContext): void { const json = jsonObject as UnknownObject; const action = json.action; @@ -55,12 +168,12 @@ export class FastTracker implements Tracker { if (json.answer === undefined) { this.processAnnounce(json, peer); } else { - this.processAnswer(json, peer); + this.processAnswer(json); } } else if (event === "started") { this.processAnnounce(json, peer); } else if (event === "stopped") { - this.processStop(json, peer); + this.processStop(json); } else if (event === "completed") { this.processAnnounce(json, peer, true); } else { @@ -73,156 +186,103 @@ export class FastTracker implements Tracker { } } - public disconnectPeer(peer: PeerContext): void { - const peerId = peer.id; - if (peerId === undefined) { - return; - } - - if (debugEnabled) { - debug("disconnect peer:", Buffer.from(peerId).toString("hex")); - } - - for (const infoHash in peer) { - const swarm = (peer as unknown as UnknownObject)[infoHash]; - - if (!(swarm instanceof Swarm)) { - continue; - } - - swarm.removePeer(peer); - delete (peer as unknown as UnknownObject)[infoHash]; + public disconnectPeersFromSocket(socket: SocketContext): void { + for (const peerId in socket) { + const peer = (socket as unknown as UnknownObject)[peerId] as PeerContext; + if (peer.peerId !== peerId) continue; // Not a peer property if (debugEnabled) { debug( - "disconnect peer: peer", - Buffer.from(peerId).toString("hex"), - "removed from swarm", - Buffer.from(infoHash).toString("hex"), + "disconnect peer:", + Buffer.from(peer.peerId).toString("hex"), + "swarm:", + Buffer.from(peer.swarm.infoHash).toString("hex"), ); } - - if (swarm.peers.length === 0) { - if (debugEnabled) { - debug( - "disconnect peer: swarm removed (empty)", - Buffer.from(swarm.infoHash).toString("hex"), - ); - } - this.#swarms.delete(swarm.infoHash); - } + this.removePeer(peer); } - - this.#peers.delete(peerId); - peer.id = undefined; } private processAnnounce( json: UnknownObject, - peer: PeerContext, + socket: SocketContext, completed = false, ): void { - const infoHash = json.info_hash; - const peerId = json.peer_id; - let swarm: unknown = undefined; + const infoHash = json.info_hash as string; + const peerId = json.peer_id as string; + let swarm: Swarm | undefined; + const isPeerCompleted = completed || json.left === 0; - if (peer.id === undefined) { - if (typeof peerId !== "string") { - throw new TrackerError("announce: peer_id field is missing or wrong"); - } + let peer = (socket as unknown as UnknownObject)[peerId] as + | PeerContext + | undefined; - peer.id = peerId; + if (peer === undefined) { + const existingPeer = this.#peers.get(peerId); + if (existingPeer) { + if (debugEnabled) { + debug( + "move peer:", + Buffer.from(existingPeer.peerId).toString("hex"), + "from swarm:", + Buffer.from(existingPeer.swarm.infoHash).toString("hex"), + "to swarm:", + Buffer.from(infoHash).toString("hex"), + ); + } - const oldPeer = this.#peers.get(peerId); - if (oldPeer !== undefined) { - this.disconnectPeer(oldPeer); + this.removePeer(existingPeer); } + swarm = this.getOrCreateSwarm(infoHash); + + peer = { + peerId, + sendMessage: socket.sendMessage, + socket, + lastAccessed: performance.now(), + swarm, + }; + + this.addPeerToSwarm(swarm, peer, isPeerCompleted); + + (socket as unknown as UnknownObject)[peerId] = peer; this.#peers.set(peerId, peer); - } else if (peer.id === peerId) { - swarm = (peer as unknown as UnknownObject)[infoHash as string]; - } else { - throw new TrackerError( - "announce: different peer_id on the same connection", - ); - } + } else if (peer.peerId === peerId) { + peer.lastAccessed = performance.now(); - const isPeerCompleted = completed || json.left === 0; + if (infoHash !== peer.swarm.infoHash) { + const oldSwarm = peer.swarm; - if (swarm === undefined) { - swarm = this.addPeerToSwarm(peer, infoHash, isPeerCompleted); - } else if (swarm instanceof Swarm) { - if (debugEnabled) { - debug( - "announce: peer", - Buffer.from(peer.id).toString("hex"), - "in swarm", - Buffer.from(infoHash as string).toString("hex"), - ); - } + this.removePeerFromSwarm(oldSwarm, peer); - if (isPeerCompleted) { - swarm.setCompleted(peer); + swarm = this.getOrCreateSwarm(infoHash); + peer.swarm = swarm; + this.addPeerToSwarm(swarm, peer, isPeerCompleted); + } else { + swarm = peer.swarm; + if (isPeerCompleted) { + this.setPeerCompletedInSwarm(swarm, peer); + } } } else { - throw new TrackerError("announce: illegal info_hash field"); + throw new TrackerError("announce: peerId mismatch"); } - peer.sendMessage( + const complete = swarm.completedPeers?.size ?? 0; + + socket.sendMessage( { action: "announce", interval: this.settings.announceInterval, info_hash: infoHash, - complete: (swarm as Swarm).completedCount, - incomplete: - (swarm as Swarm).peers.length - (swarm as Swarm).completedCount, + complete, + incomplete: swarm.peers.length - complete, }, - peer, + socket, ); - this.sendOffersToPeers( - json, - (swarm as Swarm).peers, - peer, - infoHash as string, - ); - } - - private addPeerToSwarm( - peer: PeerContext, - infoHash: unknown, - completed: boolean, - ): Swarm { - let swarm = this.#swarms.get(infoHash as string); - - if (swarm === undefined) { - if (typeof infoHash !== "string") { - throw new TrackerError("announce: info_hash field is missing or wrong"); - } - - if (debugEnabled) { - debug( - "announce: swarm created:", - Buffer.from(infoHash).toString("hex"), - ); - } - - swarm = new Swarm(infoHash); - this.#swarms.set(infoHash, swarm); - } - - if (debugEnabled) { - debug( - "announce: peer", - Buffer.from(peer.id!).toString("hex"), - "added to swarm", - Buffer.from(infoHash as string).toString("hex"), - ); - } - - swarm.addPeer(peer, completed); - (peer as unknown as UnknownObject)[infoHash as string] = swarm; - return swarm; + this.sendOffersToPeers(json, swarm.peers, peer, infoHash); } private sendOffersToPeers( @@ -260,7 +320,12 @@ export class FastTracker implements Tracker { const offersIterator = (offers as unknown[]).values(); for (const toPeer of peers) { if (toPeer !== peer) { - sendOffer(offersIterator.next().value, peer.id!, toPeer, infoHash); + sendOffer( + offersIterator.next().value, + peer.peerId, + toPeer.socket, + infoHash, + ); } } } else { @@ -273,7 +338,7 @@ export class FastTracker implements Tracker { if (toPeer === peer) { i--; // do one more iteration } else { - sendOffer(offers[i], peer.id!, toPeer, infoHash); + sendOffer(offers[i], peer.peerId, toPeer.socket, infoHash); } peerIndex++; @@ -289,60 +354,44 @@ export class FastTracker implements Tracker { ); } - private processAnswer(json: UnknownObject, peer: PeerContext): void { + private processAnswer(json: UnknownObject): void { const toPeerId = json.to_peer_id as string; const toPeer = this.#peers.get(toPeerId); if (toPeer === undefined) { throw new TrackerError("answer: to_peer_id is not in the swarm"); } - json.peer_id = peer.id; delete json.to_peer_id; - toPeer.sendMessage(json, toPeer); + toPeer.sendMessage(json, toPeer.socket); if (debugEnabled) { debug( "answer: from peer", - Buffer.from(peer.id!).toString("hex"), + Buffer.from(json.peer_id as string).toString("hex"), "to peer", Buffer.from(toPeerId).toString("hex"), ); } } - private processStop(json: UnknownObject, peer: PeerContext): void { - const infoHash = json.info_hash; - const swarm = (peer as unknown as UnknownObject)[infoHash as string]; - - if (!(swarm instanceof Swarm)) { - debug("stop event: peer not in the swarm"); - return; - } + private processStop(json: UnknownObject): void { + const peerId = json.peer_id as string; - if (debugEnabled) { - debug( - "stop event: peer", - Buffer.from(peer.id!).toString("hex"), - "removed from swarm", - Buffer.from(infoHash as string).toString("hex"), - ); - } - - swarm.removePeer(peer); - delete (peer as unknown as UnknownObject)[infoHash as string]; - - if (swarm.peers.length === 0) { + const peer = this.#peers.get(peerId); + if (peer) { if (debugEnabled) { debug( - "stop event: swarm removed (empty)", - Buffer.from(infoHash as string).toString("hex"), + "stop peer:", + Buffer.from(peer.peerId).toString("hex"), + "swarm:", + Buffer.from(peer.swarm.infoHash).toString("hex"), ); } - this.#swarms.delete(infoHash as string); + this.removePeer(peer); } } - private processScrape(json: UnknownObject, peer: PeerContext): void { + private processScrape(json: UnknownObject, socket: SocketContext): void { const infoHash = json.info_hash; const files: { [key: string]: { @@ -354,20 +403,22 @@ export class FastTracker implements Tracker { if (infoHash === undefined) { for (const swarm of this.#swarms.values()) { + const complete = swarm.completedPeers?.size ?? 0; files[swarm.infoHash] = { - complete: swarm.completedCount, - incomplete: swarm.peers.length - swarm.completedCount, - downloaded: swarm.completedCount, + complete, + incomplete: swarm.peers.length - complete, + downloaded: complete, }; } } else if (infoHash instanceof Array) { for (const singleInfoHash of infoHash as unknown[]) { const swarm = this.#swarms.get(singleInfoHash as string); if (swarm !== undefined) { + const complete = swarm.completedPeers?.size ?? 0; files[singleInfoHash as string] = { - complete: swarm.completedCount, - incomplete: swarm.peers.length - swarm.completedCount, - downloaded: swarm.completedCount, + complete, + incomplete: swarm.peers.length - complete, + downloaded: complete, }; } else if (typeof singleInfoHash === "string") { files[singleInfoHash] = { @@ -380,10 +431,11 @@ export class FastTracker implements Tracker { } else { const swarm = this.#swarms.get(infoHash as string); if (swarm !== undefined) { + const complete = swarm.completedPeers?.size ?? 0; files[infoHash as string] = { - complete: swarm.completedCount, - incomplete: swarm.peers.length - swarm.completedCount, - downloaded: swarm.completedCount, + complete, + incomplete: swarm.peers.length - complete, + downloaded: complete, }; } else if (typeof infoHash === "string") { files[infoHash] = { @@ -394,63 +446,14 @@ export class FastTracker implements Tracker { } } - peer.sendMessage({ action: "scrape", files }, peer); - } -} - -class Swarm { - public completedCount = 0; - private completedPeers?: Set; - - readonly #peers: PeerContext[] = []; - - public constructor(public readonly infoHash: string) {} - - public get peers(): readonly PeerContext[] { - return this.#peers; - } - - public addPeer(peer: PeerContext, completed: boolean): void { - this.#peers.push(peer); - if (completed) { - if (this.completedPeers === undefined) { - this.completedPeers = new Set(); - } - this.completedPeers.add(peer.id!); - this.completedCount++; - } - } - - public removePeer(peer: PeerContext): void { - const index = this.#peers.indexOf(peer); - - if (this.completedPeers?.delete(peer.id!) === true) { - this.completedCount--; - } - - // Delete peerId from array without calling splice - const last = this.#peers.pop()!; - if (index < this.#peers.length) { - this.#peers[index] = last; - } - } - - public setCompleted(peer: PeerContext): void { - if (this.completedPeers === undefined) { - this.completedPeers = new Set(); - } - - if (!this.completedPeers.has(peer.id!)) { - this.completedPeers.add(peer.id!); - this.completedCount++; - } + socket.sendMessage({ action: "scrape", files }, socket); } } function sendOffer( offerItem: unknown, fromPeerId: string, - toPeer: PeerContext, + socket: SocketContext, infoHash: string, ): void { if (!(offerItem instanceof Object)) { @@ -464,7 +467,7 @@ function sendOffer( throw new TrackerError("announce: wrong offer item field format"); } - toPeer.sendMessage( + socket.sendMessage( { action: "announce", info_hash: infoHash, @@ -475,6 +478,6 @@ function sendOffer( sdp: (offer as UnknownObject).sdp, // offer.sdp is not validated to be a string }, }, - toPeer, + socket, ); } diff --git a/lib/index.ts b/lib/index.ts index 1b133ed..c339637 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -17,4 +17,8 @@ export type { UWebSocketsTracker } from "./uws-tracker.js"; export type { FastTracker } from "./fast-tracker.js"; -export type { Tracker, PeerContext, TrackerError } from "./tracker.js"; +export type { + Tracker, + SocketContext as PeerContext, + TrackerError, +} from "./tracker.js"; diff --git a/lib/run-uws-tracker.ts b/lib/run-uws-tracker.ts index 0c65887..8800b4a 100644 --- a/lib/run-uws-tracker.ts +++ b/lib/run-uws-tracker.ts @@ -244,7 +244,7 @@ function buildServer({ peersCount += swarm.peers.length; const infoHashHex = Buffer.from(infoHash, "binary").toString("hex"); - peersCountPerInfoHash[infoHashHex] = peersCount; + peersCountPerInfoHash[infoHashHex] = swarm.peers.length; } const serversStats = new Array<{ diff --git a/lib/tracker.ts b/lib/tracker.ts index 36c2553..75e417c 100644 --- a/lib/tracker.ts +++ b/lib/tracker.ts @@ -14,16 +14,29 @@ * limitations under the License. */ +export interface SocketContext { + sendMessage: (json: object, peer: SocketContext) => void; +} + +export type Swarm = { + infoHash: string; + completedPeers?: Set; + peers: PeerContext[]; +}; + export interface PeerContext { - id?: string; - sendMessage: (json: object, peer: PeerContext) => void; + peerId: string; + sendMessage: (json: object, peer: SocketContext) => void; + socket: SocketContext; + lastAccessed: number; + swarm: Swarm; } export interface Tracker { readonly swarms: ReadonlyMap; readonly settings: object; - processMessage: (json: object, peer: PeerContext) => void; - disconnectPeer: (peer: PeerContext) => void; + processMessage: (json: object, peer: SocketContext) => void; + disconnectPeersFromSocket: (peer: SocketContext) => void; } export class TrackerError extends Error {} diff --git a/lib/uws-tracker.ts b/lib/uws-tracker.ts index 84b5200..0650c62 100644 --- a/lib/uws-tracker.ts +++ b/lib/uws-tracker.ts @@ -25,7 +25,7 @@ import { HttpResponse, } from "uWebSockets.js"; import Debug from "debug"; -import { Tracker, TrackerError, PeerContext } from "./tracker.js"; +import { Tracker, TrackerError, SocketContext } from "./tracker.js"; import { ServerSettings, WebSocketsSettings, @@ -33,8 +33,8 @@ import { } from "./run-uws-tracker.js"; declare module "./tracker.js" { - interface PeerContext { - ws: WebSocket; + interface SocketContext { + ws: WebSocket; } } @@ -186,7 +186,7 @@ export class UWebSocketsTracker { idleTimeout: this.settings.websockets.idleTimeout, open: this.onOpen, upgrade: this.onUpgrade, - drain: (ws: WebSocket) => { + drain: (ws: WebSocket) => { if (debugWebSocketsEnabled) { debugWebSockets("drain", ws.getBufferedAmount()); } @@ -276,7 +276,7 @@ export class UWebSocketsTracker { ); } - response.upgrade>( + response.upgrade>( { sendMessage, }, @@ -288,7 +288,7 @@ export class UWebSocketsTracker { }; private readonly onMessage = ( - ws: WebSocket, + ws: WebSocket, message: ArrayBuffer, ): void => { debugWebSockets("message of size", message.byteLength); @@ -308,13 +308,7 @@ export class UWebSocketsTracker { } if (debugMessagesEnabled) { - debugMessages( - "in", - userData.id === undefined - ? "unknown peer" - : Buffer.from(userData.id).toString("hex"), - json, - ); + debugMessages("in", json); } try { @@ -330,28 +324,22 @@ export class UWebSocketsTracker { }; private readonly onClose = ( - ws: WebSocket, + ws: WebSocket, code: number, ): void => { this.webSocketsCount--; if (ws.getUserData().sendMessage !== undefined) { - this.tracker.disconnectPeer(ws as unknown as PeerContext); + this.tracker.disconnectPeersFromSocket(ws as unknown as SocketContext); } debugWebSockets("closed with code", code); }; } -function sendMessage(json: object, peerContext: PeerContext): void { +function sendMessage(json: object, peerContext: SocketContext): void { peerContext.ws.send(JSON.stringify(json), false, false); if (debugMessagesEnabled) { - debugMessages( - "out", - peerContext.id === undefined - ? "unknown peer" - : Buffer.from(peerContext.id).toString("hex"), - json, - ); + debugMessages("out", json); } } diff --git a/package-lock.json b/package-lock.json index 3efa98f..5152607 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,27 +9,27 @@ "version": "0.0.1", "license": "Apache-2.0", "dependencies": { - "debug": "^4.3.4", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.42.0" + "debug": "^4.3.5", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.44.0" }, "bin": { "wt-tracker": "bin/wt-tracker" }, "devDependencies": { - "@types/chai": "^4.3.11", + "@types/chai": "^4.3.16", "@types/debug": "^4.1.12", "@types/mocha": "^10.0.6", - "@types/node": "^20.11.19", + "@types/node": "^20.14.5", "@types/ws": "^8.5.10", - "@vitest/coverage-v8": "^1.3.0", + "@vitest/coverage-v8": "^1.6.0", "eslint": "^8.56.0", - "prettier": "^3.2.5", - "rimraf": "^5.0.5", + "prettier": "^3.3.2", + "rimraf": "^5.0.7", "ts-mockito": "^2.6.1", - "typescript": "^5.3.3", - "typescript-eslint": "^7.0.2", - "vitest": "^1.3.0", - "ws": "^8.16.0" + "typescript": "^5.4.5", + "typescript-eslint": "^7.13.1", + "vitest": "^1.6.0", + "ws": "^8.17.1" }, "engines": { "node": ">=16.0.0" @@ -108,9 +108,9 @@ "dev": true }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", - "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", "cpu": [ "ppc64" ], @@ -124,9 +124,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", - "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", "cpu": [ "arm" ], @@ -140,9 +140,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", - "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", "cpu": [ "arm64" ], @@ -156,9 +156,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", - "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", "cpu": [ "x64" ], @@ -172,9 +172,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", - "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -188,9 +188,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", - "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", "cpu": [ "x64" ], @@ -204,9 +204,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", - "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", "cpu": [ "arm64" ], @@ -220,9 +220,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", - "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", "cpu": [ "x64" ], @@ -236,9 +236,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", - "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", "cpu": [ "arm" ], @@ -252,9 +252,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", - "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", "cpu": [ "arm64" ], @@ -268,9 +268,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", - "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", "cpu": [ "ia32" ], @@ -284,9 +284,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", - "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", "cpu": [ "loong64" ], @@ -300,9 +300,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", - "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", "cpu": [ "mips64el" ], @@ -316,9 +316,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", - "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", "cpu": [ "ppc64" ], @@ -332,9 +332,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", - "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", "cpu": [ "riscv64" ], @@ -348,9 +348,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", - "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", "cpu": [ "s390x" ], @@ -364,9 +364,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", - "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", "cpu": [ "x64" ], @@ -380,9 +380,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", - "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", "cpu": [ "x64" ], @@ -396,9 +396,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", - "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", "cpu": [ "x64" ], @@ -412,9 +412,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", - "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", "cpu": [ "x64" ], @@ -428,9 +428,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", - "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", "cpu": [ "arm64" ], @@ -444,9 +444,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", - "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", "cpu": [ "ia32" ], @@ -460,9 +460,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", - "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", "cpu": [ "x64" ], @@ -668,9 +668,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -723,9 +723,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz", - "integrity": "sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", "cpu": [ "arm" ], @@ -736,9 +736,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.12.0.tgz", - "integrity": "sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", "cpu": [ "arm64" ], @@ -749,9 +749,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.12.0.tgz", - "integrity": "sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", "cpu": [ "arm64" ], @@ -762,9 +762,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.12.0.tgz", - "integrity": "sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", "cpu": [ "x64" ], @@ -775,9 +775,22 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.12.0.tgz", - "integrity": "sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", "cpu": [ "arm" ], @@ -788,9 +801,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.12.0.tgz", - "integrity": "sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", "cpu": [ "arm64" ], @@ -801,9 +814,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.12.0.tgz", - "integrity": "sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", "cpu": [ "arm64" ], @@ -813,10 +826,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.12.0.tgz", - "integrity": "sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", "cpu": [ "riscv64" ], @@ -826,10 +852,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.12.0.tgz", - "integrity": "sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", "cpu": [ "x64" ], @@ -840,9 +879,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.12.0.tgz", - "integrity": "sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", "cpu": [ "x64" ], @@ -853,9 +892,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.12.0.tgz", - "integrity": "sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", "cpu": [ "arm64" ], @@ -866,9 +905,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.12.0.tgz", - "integrity": "sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", "cpu": [ "ia32" ], @@ -879,9 +918,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.12.0.tgz", - "integrity": "sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", "cpu": [ "x64" ], @@ -898,9 +937,9 @@ "dev": true }, "node_modules/@types/chai": { - "version": "4.3.11", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", - "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", + "version": "4.3.16", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.16.tgz", + "integrity": "sha512-PatH4iOdyh3MyWtmHVFXLWCCIhUbopaltqddG9BzB+gMIzee2MJrvd+jouii9Z3wzQJruGWAm7WOMjgfG8hQlQ==", "dev": true }, "node_modules/@types/debug": { @@ -918,18 +957,6 @@ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, "node_modules/@types/mocha": { "version": "10.0.6", "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", @@ -943,20 +970,14 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.11.19", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", - "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", + "version": "20.14.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.5.tgz", + "integrity": "sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==", "dev": true, "dependencies": { "undici-types": "~5.26.4" } }, - "node_modules/@types/semver": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", - "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", - "dev": true - }, "node_modules/@types/ws": { "version": "8.5.10", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", @@ -967,25 +988,23 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.0.2.tgz", - "integrity": "sha512-/XtVZJtbaphtdrWjr+CJclaCVGPtOdBpFEnvtNf/jRV0IiEemRrL0qABex/nEt8isYcnFacm3nPHYQwL+Wb7qg==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz", + "integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/type-utils": "7.0.2", - "@typescript-eslint/utils": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/type-utils": "7.13.1", + "@typescript-eslint/utils": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1002,19 +1021,19 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.2.tgz", - "integrity": "sha512-GdwfDglCxSmU+QTS9vhz2Sop46ebNCXpPPvsByK7hu0rFGRHL+AusKQJ7SoN+LbLh6APFpQwHKmDSwN35Z700Q==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz", + "integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/typescript-estree": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1030,16 +1049,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", - "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz", + "integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2" + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1047,18 +1066,18 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.2.tgz", - "integrity": "sha512-IKKDcFsKAYlk8Rs4wiFfEwJTQlHcdn8CLwLaxwd6zb8HNiMcQIFX9sWax2k4Cjj7l7mGS5N1zl7RCHOVwHq2VQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz", + "integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.0.2", - "@typescript-eslint/utils": "7.0.2", + "@typescript-eslint/typescript-estree": "7.13.1", + "@typescript-eslint/utils": "7.13.1", "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1074,12 +1093,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", - "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz", + "integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1087,22 +1106,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", - "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz", + "integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/visitor-keys": "7.13.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1124,9 +1143,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" @@ -1139,21 +1158,18 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", - "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz", + "integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/typescript-estree": "7.0.2", - "semver": "^7.5.4" + "@typescript-eslint/scope-manager": "7.13.1", + "@typescript-eslint/types": "7.13.1", + "@typescript-eslint/typescript-estree": "7.13.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1164,16 +1180,16 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", - "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz", + "integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.13.1", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -1187,9 +1203,9 @@ "dev": true }, "node_modules/@vitest/coverage-v8": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.3.0.tgz", - "integrity": "sha512-e5Y5uK5NNoQMQaNitGQQjo9FoA5ZNcu7Bn6pH+dxUf48u6po1cX38kFBYUHZ9GNVkF4JLbncE0WeWwTw+nLrxg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.0.tgz", + "integrity": "sha512-KvapcbMY/8GYIG0rlwwOKCVNRc0OL20rrhFkg/CHNzncV03TE2XWvO5w9uZYoxNiMEBacAJt3unSOiZ7svePew==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.1", @@ -1197,30 +1213,30 @@ "debug": "^4.3.4", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^4.0.1", + "istanbul-lib-source-maps": "^5.0.4", "istanbul-reports": "^3.1.6", "magic-string": "^0.30.5", "magicast": "^0.3.3", "picocolors": "^1.0.0", "std-env": "^3.5.0", - "test-exclude": "^6.0.0", - "v8-to-istanbul": "^9.2.0" + "strip-literal": "^2.0.0", + "test-exclude": "^6.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "vitest": "1.3.0" + "vitest": "1.6.0" } }, "node_modules/@vitest/expect": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.3.0.tgz", - "integrity": "sha512-7bWt0vBTZj08B+Ikv70AnLRicohYwFgzNjFqo9SxxqHHxSlUJGSXmCRORhOnRMisiUryKMdvsi1n27Bc6jL9DQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", + "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", "dev": true, "dependencies": { - "@vitest/spy": "1.3.0", - "@vitest/utils": "1.3.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "chai": "^4.3.10" }, "funding": { @@ -1228,12 +1244,12 @@ } }, "node_modules/@vitest/runner": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.3.0.tgz", - "integrity": "sha512-1Jb15Vo/Oy7mwZ5bXi7zbgszsdIBNjc4IqP8Jpr/8RdBC4nF1CTzIAn2dxYvpF1nGSseeL39lfLQ2uvs5u1Y9A==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", + "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", "dev": true, "dependencies": { - "@vitest/utils": "1.3.0", + "@vitest/utils": "1.6.0", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -1269,9 +1285,9 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.3.0.tgz", - "integrity": "sha512-swmktcviVVPYx9U4SEQXLV6AEY51Y6bZ14jA2yo6TgMxQ3h+ZYiO0YhAHGJNp0ohCFbPAis1R9kK0cvN6lDPQA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", + "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", "dev": true, "dependencies": { "magic-string": "^0.30.5", @@ -1283,9 +1299,9 @@ } }, "node_modules/@vitest/spy": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.3.0.tgz", - "integrity": "sha512-AkCU0ThZunMvblDpPKgjIi025UxR8V7MZ/g/EwmAGpjIujLVV2X6rGYGmxE2D4FJbAy0/ijdROHMWa2M/6JVMw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", + "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", "dev": true, "dependencies": { "tinyspy": "^2.2.0" @@ -1295,9 +1311,9 @@ } }, "node_modules/@vitest/utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.3.0.tgz", - "integrity": "sha512-/LibEY/fkaXQufi4GDlQZhikQsPO2entBKtfuyIpr1jV4DpaeasqkeHjhdOhU24vSHshcSuEyVlWdzvv2XmYCw==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", + "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", "dev": true, "dependencies": { "diff-sequences": "^29.6.3", @@ -1331,10 +1347,13 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } @@ -1420,12 +1439,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1519,10 +1538,10 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "node_modules/confbox": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", + "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", "dev": true }, "node_modules/cross-spawn": { @@ -1540,9 +1559,9 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -1556,9 +1575,9 @@ } }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, "dependencies": { "type-detect": "^4.0.0" @@ -1619,9 +1638,9 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.19.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", - "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "bin": { @@ -1631,29 +1650,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.19.12", - "@esbuild/android-arm": "0.19.12", - "@esbuild/android-arm64": "0.19.12", - "@esbuild/android-x64": "0.19.12", - "@esbuild/darwin-arm64": "0.19.12", - "@esbuild/darwin-x64": "0.19.12", - "@esbuild/freebsd-arm64": "0.19.12", - "@esbuild/freebsd-x64": "0.19.12", - "@esbuild/linux-arm": "0.19.12", - "@esbuild/linux-arm64": "0.19.12", - "@esbuild/linux-ia32": "0.19.12", - "@esbuild/linux-loong64": "0.19.12", - "@esbuild/linux-mips64el": "0.19.12", - "@esbuild/linux-ppc64": "0.19.12", - "@esbuild/linux-riscv64": "0.19.12", - "@esbuild/linux-s390x": "0.19.12", - "@esbuild/linux-x64": "0.19.12", - "@esbuild/netbsd-x64": "0.19.12", - "@esbuild/openbsd-x64": "0.19.12", - "@esbuild/sunos-x64": "0.19.12", - "@esbuild/win32-arm64": "0.19.12", - "@esbuild/win32-ia32": "0.19.12", - "@esbuild/win32-x64": "0.19.12" + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" } }, "node_modules/escape-string-regexp": { @@ -1910,9 +1929,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -2312,14 +2331,14 @@ } }, "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.4.tgz", + "integrity": "sha512-wHOoEsNJTVltaJp8eVkm8w+GVkVNHT2YDYo53YdzQEL2gWm1hBX5cGFR9hQJtuGLebidVX7et3+dmDZrmclduw==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" + "istanbul-lib-coverage": "^3.0.0" }, "engines": { "node": ">=10" @@ -2357,9 +2376,9 @@ } }, "node_modules/js-tokens": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-8.0.3.tgz", - "integrity": "sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.0.tgz", + "integrity": "sha512-WriZw1luRMlmV3LGJaR6QOJjWwgLUTf89OwT2lUOyjX2dJGBwgmIkbcz+7WFZjrZM635JOIR517++e/67CP9dQ==", "dev": true }, "node_modules/js-yaml": { @@ -2392,12 +2411,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/jsonc-parser": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", - "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", - "dev": true - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2482,15 +2495,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", - "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/magicast": { @@ -2535,12 +2545,12 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -2581,15 +2591,15 @@ } }, "node_modules/mlly": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.5.0.tgz", - "integrity": "sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.1.tgz", + "integrity": "sha512-rrVRZRELyQzrIUAVMHxP97kv+G786pHmOKzuFII8zDYahFBS7qnHh2AlYSl1GAHhaMPCz6/oHjVMcfFYgFYHgA==", "dev": true, "dependencies": { "acorn": "^8.11.3", "pathe": "^1.1.2", - "pkg-types": "^1.0.3", - "ufo": "^1.3.2" + "pkg-types": "^1.1.1", + "ufo": "^1.5.3" } }, "node_modules/ms": { @@ -2622,9 +2632,9 @@ "dev": true }, "node_modules/npm-run-path": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.2.0.tgz", - "integrity": "sha512-W4/tgAXFqFA0iL7fk0+uQ3g7wkL8xJmx3XdK0VGb4cHW//eZTtKGvFBBoRKVTpY7n6ze4NL9ly7rgXcHufqXKg==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", + "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, "dependencies": { "path-key": "^4.0.0" @@ -2799,9 +2809,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -2817,20 +2827,20 @@ } }, "node_modules/pkg-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz", - "integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", + "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", "dev": true, "dependencies": { - "jsonc-parser": "^3.2.0", - "mlly": "^1.2.0", - "pathe": "^1.1.0" + "confbox": "^0.1.7", + "mlly": "^1.7.0", + "pathe": "^1.1.2" } }, "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "funding": [ { @@ -2849,7 +2859,7 @@ "dependencies": { "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -2865,9 +2875,9 @@ } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz", + "integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -2935,9 +2945,9 @@ ] }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", "dev": true }, "node_modules/resolve-from": { @@ -2960,9 +2970,9 @@ } }, "node_modules/rimraf": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", - "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", "dev": true, "dependencies": { "glob": "^10.3.7" @@ -2971,16 +2981,16 @@ "rimraf": "dist/esm/bin.mjs" }, "engines": { - "node": ">=14" + "node": ">=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/rollup": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.12.0.tgz", - "integrity": "sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -2993,19 +3003,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.12.0", - "@rollup/rollup-android-arm64": "4.12.0", - "@rollup/rollup-darwin-arm64": "4.12.0", - "@rollup/rollup-darwin-x64": "4.12.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.12.0", - "@rollup/rollup-linux-arm64-gnu": "4.12.0", - "@rollup/rollup-linux-arm64-musl": "4.12.0", - "@rollup/rollup-linux-riscv64-gnu": "4.12.0", - "@rollup/rollup-linux-x64-gnu": "4.12.0", - "@rollup/rollup-linux-x64-musl": "4.12.0", - "@rollup/rollup-win32-arm64-msvc": "4.12.0", - "@rollup/rollup-win32-ia32-msvc": "4.12.0", - "@rollup/rollup-win32-x64-msvc": "4.12.0", + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", "fsevents": "~2.3.2" } }, @@ -3107,19 +3120,10 @@ "node": ">=8" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -3252,12 +3256,12 @@ } }, "node_modules/strip-literal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.0.0.tgz", - "integrity": "sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.0.tgz", + "integrity": "sha512-Op+UycaUt/8FbN/Z2TWPBLge3jWrP3xj10f3fnYxf052bKuS3EKs1ZQcVGjnEMdsNVAM+plXRdmjrZ/KgG3Skw==", "dev": true, "dependencies": { - "js-tokens": "^8.0.2" + "js-tokens": "^9.0.0" }, "funding": { "url": "https://github.com/sponsors/antfu" @@ -3316,15 +3320,15 @@ "dev": true }, "node_modules/tinybench": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.6.0.tgz", - "integrity": "sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", + "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", "dev": true }, "node_modules/tinypool": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.2.tgz", - "integrity": "sha512-SUszKYe5wgsxnNOVlBYO6IC+8VGWdVGZWAqUxp3UErNBtptZvWbwyUOyzNL59zigz2rCA92QiL3wvG+JDSdJdQ==", + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", + "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", "dev": true, "engines": { "node": ">=14.0.0" @@ -3361,9 +3365,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { "node": ">=16" @@ -3415,9 +3419,9 @@ } }, "node_modules/typescript": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", - "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -3428,16 +3432,17 @@ } }, "node_modules/typescript-eslint": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.0.2.tgz", - "integrity": "sha512-Nsb+Dfi897ErE3CtVJYBECBQWPGEpCXLqLCQarBhFtyJsHnhA7O39GmtAmN3dmZ6bIp8tP5T+AOUrEdE07SBVg==", + "version": "7.13.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.13.1.tgz", + "integrity": "sha512-pvLEuRs8iS9s3Cnp/Wt//hpK8nKc8hVa3cLljHqzaJJQYP8oys8GUyIFqtlev+2lT/fqMPcyQko+HJ6iYK3nFA==", "dev": true, "dependencies": { - "@typescript-eslint/eslint-plugin": "7.0.2", - "@typescript-eslint/parser": "7.0.2" + "@typescript-eslint/eslint-plugin": "7.13.1", + "@typescript-eslint/parser": "7.13.1", + "@typescript-eslint/utils": "7.13.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -3453,9 +3458,9 @@ } }, "node_modules/ufo": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.4.0.tgz", - "integrity": "sha512-Hhy+BhRBleFjpJ2vchUNN40qgkh0366FWJGqVLYBHev0vpHTrXSA0ryT+74UiW6KWsldNurQMKGqCm1M2zBciQ==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", + "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", "dev": true }, "node_modules/undici-types": { @@ -3478,29 +3483,15 @@ "resolved": "git+ssh://git@github.com/uNetworking/uWebSockets.js.git#f40213ec0a97d0d8721d9d32d92d6eb6ddcd22e7", "license": "Apache-2.0" }, - "node_modules/v8-to-istanbul": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", - "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^2.0.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, "node_modules/vite": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.3.tgz", - "integrity": "sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.3.1.tgz", + "integrity": "sha512-XBmSKRLXLxiaPYamLv3/hnP/KXDai1NDexN0FpkTaZXTfycHvkRHoenpgl/fvuK/kPbB6xAgoyiryAhQNxYmAQ==", "dev": true, "dependencies": { - "esbuild": "^0.19.3", - "postcss": "^8.4.35", - "rollup": "^4.2.0" + "esbuild": "^0.21.3", + "postcss": "^8.4.38", + "rollup": "^4.13.0" }, "bin": { "vite": "bin/vite.js" @@ -3548,9 +3539,9 @@ } }, "node_modules/vite-node": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.3.0.tgz", - "integrity": "sha512-D/oiDVBw75XMnjAXne/4feCkCEwcbr2SU1bjAhCcfI5Bq3VoOHji8/wCPAfUkDIeohJ5nSZ39fNxM3dNZ6OBOA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", + "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", "dev": true, "dependencies": { "cac": "^6.7.14", @@ -3570,16 +3561,16 @@ } }, "node_modules/vitest": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.3.0.tgz", - "integrity": "sha512-V9qb276J1jjSx9xb75T2VoYXdO1UKi+qfflY7V7w93jzX7oA/+RtYE6TcifxksxsZvygSSMwu2Uw6di7yqDMwg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", + "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", "dev": true, "dependencies": { - "@vitest/expect": "1.3.0", - "@vitest/runner": "1.3.0", - "@vitest/snapshot": "1.3.0", - "@vitest/spy": "1.3.0", - "@vitest/utils": "1.3.0", + "@vitest/expect": "1.6.0", + "@vitest/runner": "1.6.0", + "@vitest/snapshot": "1.6.0", + "@vitest/spy": "1.6.0", + "@vitest/utils": "1.6.0", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -3591,9 +3582,9 @@ "std-env": "^3.5.0", "strip-literal": "^2.0.0", "tinybench": "^2.5.1", - "tinypool": "^0.8.2", + "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.3.0", + "vite-node": "1.6.0", "why-is-node-running": "^2.2.2" }, "bin": { @@ -3608,8 +3599,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.3.0", - "@vitest/ui": "1.3.0", + "@vitest/browser": "1.6.0", + "@vitest/ui": "1.6.0", "happy-dom": "*", "jsdom": "*" }, @@ -3766,9 +3757,9 @@ "dev": true }, "node_modules/ws": { - "version": "8.16.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", - "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "engines": { "node": ">=10.0.0" diff --git a/package.json b/package.json index 4119831..fb638b4 100644 --- a/package.json +++ b/package.json @@ -42,23 +42,23 @@ "url": "https://github.com/Novage/wt-tracker.git" }, "dependencies": { - "debug": "^4.3.4", - "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.42.0" + "debug": "^4.3.5", + "uWebSockets.js": "github:uNetworking/uWebSockets.js#v20.44.0" }, "devDependencies": { - "@types/chai": "^4.3.11", + "@types/chai": "^4.3.16", "@types/debug": "^4.1.12", "@types/mocha": "^10.0.6", - "@types/node": "^20.11.19", + "@types/node": "^20.14.5", "@types/ws": "^8.5.10", - "@vitest/coverage-v8": "^1.3.0", + "@vitest/coverage-v8": "^1.6.0", "eslint": "^8.56.0", - "prettier": "^3.2.5", - "rimraf": "^5.0.5", + "prettier": "^3.3.2", + "rimraf": "^5.0.7", "ts-mockito": "^2.6.1", - "typescript": "^5.3.3", - "typescript-eslint": "^7.0.2", - "vitest": "^1.3.0", - "ws": "^8.16.0" + "typescript": "^5.4.5", + "typescript-eslint": "^7.13.1", + "vitest": "^1.6.0", + "ws": "^8.17.1" } } diff --git a/test/announce.test.ts b/test/announce.test.ts index e414867..aa8c46c 100644 --- a/test/announce.test.ts +++ b/test/announce.test.ts @@ -27,48 +27,54 @@ import { resetCalls, } from "ts-mockito"; -class PeerContextClass implements PeerContext { - public id?: string; - public swarm1?: any; - public swarm2?: any; - public swarm3?: any; - public sendMessage: (json: any, peer: PeerContext) => void = () => {}; -} - describe("announce", () => { it("should add peers to swarms on announce", () => { const tracker = new FastTracker(); - const peer0 = new PeerContextClass(); - let announceMessage: any = { + const peer0 = { + sendMessage: () => {}, + }; + let announceMessage = { action: "announce", event: "started", info_hash: "swarm1", peer_id: "0", - offers: new Array(), + offers: new Array(), numwant: 100, }; tracker.processMessage(announceMessage, peer0); + const peerContext0 = tracker.swarms + .get("swarm1") + ?.peers.find((pd) => pd.peerId === "0"); + expect(tracker.swarms).to.have.all.keys("swarm1"); expect(tracker.swarms.get("swarm1")!.peers).to.have.lengthOf(1); - expect(tracker.swarms.get("swarm1")!.peers).to.include.members([peer0]); + expect(tracker.swarms.get("swarm1")!.peers).to.include.members([ + peerContext0, + ]); - const peer1 = new PeerContextClass(); + const peer1 = { + sendMessage: () => {}, + }; announceMessage = { action: "announce", info_hash: "swarm1", peer_id: "1", - offers: new Array(), + offers: new Array(), numwant: 100, }; tracker.processMessage(announceMessage, peer1); + const peerContext1 = tracker.swarms + .get("swarm1") + ?.peers.find((pd) => pd.peerId === "1"); + expect(tracker.swarms).to.have.all.keys("swarm1"); expect(tracker.swarms.get("swarm1")!.peers).to.have.lengthOf(2); expect(tracker.swarms.get("swarm1")!.peers).to.include.members([ - peer0, - peer1, + peerContext0, + peerContext1, ]); announceMessage = { @@ -76,7 +82,7 @@ describe("announce", () => { event: "started", info_hash: "swarm1", peer_id: "1", - offers: new Array(), + offers: new Array(), numwant: 100, }; tracker.processMessage(announceMessage, peer1); @@ -84,11 +90,13 @@ describe("announce", () => { expect(tracker.swarms).to.have.all.keys("swarm1"); expect(tracker.swarms.get("swarm1")!.peers).to.have.lengthOf(2); expect(tracker.swarms.get("swarm1")!.peers).to.include.members([ - peer0, - peer1, + peerContext0, + peerContext1, ]); - const peer2 = new PeerContextClass(); + const peer2 = { + sendMessage: () => {}, + }; announceMessage = { action: "announce", event: "completed", @@ -99,36 +107,48 @@ describe("announce", () => { }; tracker.processMessage(announceMessage, peer2); + const peerContext2_2 = tracker.swarms + .get("swarm2") + ?.peers.find((pd) => pd.peerId === "2_0"); + expect(tracker.swarms).to.have.all.keys("swarm1", "swarm2"); expect(tracker.swarms.get("swarm1")!.peers).to.have.lengthOf(2); expect(tracker.swarms.get("swarm1")!.peers).to.include.members([ - peer0, - peer1, + peerContext0, + peerContext1, ]); expect(tracker.swarms.get("swarm2")!.peers).to.have.lengthOf(1); - expect(tracker.swarms.get("swarm2")!.peers).to.include.members([peer2]); + expect(tracker.swarms.get("swarm2")!.peers).to.include.members([ + peerContext2_2, + ]); - const peer3 = new PeerContextClass(); + const peer3 = { + sendMessage: () => {}, + }; announceMessage = { action: "announce", event: "completed", info_hash: "swarm2", peer_id: "2_1", - offers: new Array(), + offers: new Array(), numwant: 100, }; tracker.processMessage(announceMessage, peer3); + const peerContext2_1 = tracker.swarms + .get("swarm2")! + .peers.find((pd) => pd.peerId === "2_1"); + expect(tracker.swarms).to.have.all.keys("swarm1", "swarm2"); expect(tracker.swarms.get("swarm1")!.peers).to.have.lengthOf(2); expect(tracker.swarms.get("swarm1")!.peers).to.include.members([ - peer0, - peer1, + peerContext0, + peerContext1, ]); expect(tracker.swarms.get("swarm2")!.peers).to.have.lengthOf(2); expect(tracker.swarms.get("swarm2")!.peers).to.include.members([ - peer2, - peer3, + peerContext2_1, + peerContext2_2, ]); announceMessage = { @@ -136,357 +156,21 @@ describe("announce", () => { event: "completed", info_hash: "swarm2", peer_id: "1", - offers: new Array(), + offers: new Array(), numwant: 100, }; tracker.processMessage(announceMessage, peer1); expect(tracker.swarms).to.have.all.keys("swarm1", "swarm2"); - expect(tracker.swarms.get("swarm1")!.peers).to.have.lengthOf(2); + expect(tracker.swarms.get("swarm1")!.peers).to.have.lengthOf(1); expect(tracker.swarms.get("swarm1")!.peers).to.include.members([ - peer0, - peer1, + peerContext0, ]); expect(tracker.swarms.get("swarm2")!.peers).to.have.lengthOf(3); expect(tracker.swarms.get("swarm2")!.peers).to.include.members([ - peer1, - peer2, - peer3, + peerContext1, + peerContext2_1, + peerContext2_2, ]); }); - - it("should send offers to peers in a swarm", () => { - const tracker = new FastTracker(); - - const offers: any[] = []; - for (let i = 0; i < 10; i++) { - offers.push({ - offer: { sdp: "x" }, - offer_id: "y", - }); - } - - const mockedPeer0 = mock(PeerContextClass); - const peer0 = instance(mockedPeer0); - peer0.id = undefined; - peer0.swarm1 = undefined; - let announceMessage: any = { - action: "announce", - event: "started", - info_hash: "swarm1", - peer_id: "0", - offers: offers, - numwant: offers.length, - }; - tracker.processMessage(announceMessage, peer0); - - verify(mockedPeer0.sendMessage(anything(), peer0)).once(); - let [json] = capture(mockedPeer0.sendMessage).first(); - expect(json.info_hash).to.be.equal("swarm1"); - expect(json.complete).to.be.equal(0); - expect(json.incomplete).to.be.equal(1); - - resetCalls(mockedPeer0); - - const mockedPeer1 = mock(PeerContextClass); - const peer1 = instance(mockedPeer1); - peer1.id = undefined; - peer1.swarm1 = undefined; - peer1.swarm2 = undefined; - announceMessage = { - action: "announce", - event: "completed", - info_hash: "swarm1", - peer_id: "1", - offers: offers, - numwant: offers.length, - }; - tracker.processMessage(announceMessage, peer1); - - verify(mockedPeer1.sendMessage(anything(), peer1)).once(); - [json] = capture(mockedPeer1.sendMessage).first(); - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm1"); - expect(json.complete).to.be.equal(1); - expect(json.incomplete).to.be.equal(1); - - verify(mockedPeer0.sendMessage(anything(), peer0)).once(); - [json] = capture(mockedPeer0.sendMessage).first(); - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm1"); - expect(json.peer_id).to.be.equal("1"); - expect(json.offer_id).to.be.equal("y"); - expect(json.offer).to.exist; - expect(json.offer.type).to.be.equal("offer"); - expect(json.offer.sdp).to.be.equal("x"); - - resetCalls(mockedPeer0); - resetCalls(mockedPeer1); - - const mockedPeer2 = mock(PeerContextClass); - const peer2 = instance(mockedPeer2); - peer2.id = undefined; - peer2.swarm2 = undefined; - announceMessage = { - action: "announce", - event: "started", - info_hash: "swarm2", - peer_id: "2", - offers: offers, - numwant: offers.length, - }; - tracker.processMessage(announceMessage, peer2); - - verify(mockedPeer2.sendMessage(anything(), peer2)).once(); - [json] = capture(mockedPeer2.sendMessage).first(); - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm2"); - expect(json.complete).to.be.equal(0); - expect(json.incomplete).to.be.equal(1); - - verify(mockedPeer0.sendMessage(anything(), peer0)).never(); - verify(mockedPeer1.sendMessage(anything(), peer1)).never(); - - resetCalls(mockedPeer0); - resetCalls(mockedPeer1); - resetCalls(mockedPeer2); - - const mockedPeer3 = mock(PeerContextClass); - const peer3 = instance(mockedPeer3); - peer3.id = undefined; - peer3.swarm2 = undefined; - announceMessage = { - action: "announce", - event: "completed", - info_hash: "swarm2", - peer_id: "3", - offers: offers, - numwant: offers.length, - }; - tracker.processMessage(announceMessage, peer3); - - verify(mockedPeer3.sendMessage(anything(), peer3)).once(); - const [json3] = capture(mockedPeer3.sendMessage).first(); - expect(json.action).to.be.equal("announce"); - expect(json3.info_hash).to.be.equal("swarm2"); - expect(json3.complete).to.be.equal(1); - expect(json3.incomplete).to.be.equal(1); - - verify(mockedPeer0.sendMessage(anything(), peer0)).never(); - verify(mockedPeer1.sendMessage(anything(), peer1)).never(); - verify(mockedPeer2.sendMessage(anything(), peer2)).once(); - [json] = capture(mockedPeer2.sendMessage).first(); - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm2"); - expect(json.peer_id).to.be.equal("3"); - expect(json.offer_id).to.be.equal("y"); - expect(json.offer).to.exist; - expect(json.offer.type).to.be.equal("offer"); - expect(json.offer.sdp).to.be.equal("x"); - - resetCalls(mockedPeer0); - resetCalls(mockedPeer1); - resetCalls(mockedPeer2); - resetCalls(mockedPeer3); - - const mockedPeer4 = mock(PeerContextClass); - const peer4 = instance(mockedPeer4); - peer4.id = undefined; - peer4.swarm2 = undefined; - announceMessage = { - action: "announce", - event: "completed", - info_hash: "swarm2", - peer_id: "4", - offers: offers, - numwant: 1, - }; - tracker.processMessage(announceMessage, peer4); - - verify(mockedPeer4.sendMessage(anything(), peer4)).once(); - [json] = capture(mockedPeer4.sendMessage).first(); - expect(json.info_hash).to.be.equal("swarm2"); - expect(json.complete).to.be.equal(2); - expect(json.incomplete).to.be.equal(1); - - verify(mockedPeer0.sendMessage(anything(), peer0)).never(); - verify(mockedPeer1.sendMessage(anything(), peer1)).never(); - - try { - verify(mockedPeer2.sendMessage(anything(), peer2)).once(); - verify(mockedPeer3.sendMessage(anything(), peer3)).never(); - [json] = capture(mockedPeer2.sendMessage).first(); - } catch { - verify(mockedPeer3.sendMessage(anything(), peer3)).once(); - verify(mockedPeer2.sendMessage(anything(), peer2)).never(); - [json] = capture(mockedPeer3.sendMessage).first(); - } - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm2"); - expect(json.peer_id).to.be.equal("4"); - expect(json.offer_id).to.be.equal("y"); - expect(json.offer).to.exist; - expect(json.offer.type).to.be.equal("offer"); - expect(json.offer.sdp).to.be.equal("x"); - - resetCalls(mockedPeer0); - resetCalls(mockedPeer1); - resetCalls(mockedPeer2); - resetCalls(mockedPeer3); - resetCalls(mockedPeer4); - - announceMessage = { - action: "announce", - event: "completed", - info_hash: "swarm2", - peer_id: "1", - offers: offers, - numwant: offers.length, - }; - tracker.processMessage(announceMessage, peer1); - - verify(mockedPeer0.sendMessage(anything(), peer0)).never(); - verify(mockedPeer1.sendMessage(anything(), peer1)).once(); - verify(mockedPeer2.sendMessage(anything(), peer2)).once(); - verify(mockedPeer3.sendMessage(anything(), peer3)).once(); - verify(mockedPeer4.sendMessage(anything(), peer4)).once(); - }); - - it("should process answer messages", () => { - const tracker = new FastTracker(); - - const peer1 = { - sendMessage: (json: any) => { - if (!json.offer) { - return; - } - const answerMessage = { - action: "announce", - info_hash: json.info_hash, - peer_id: "1", - to_peer_id: json.peer_id, - answer: { - type: "answer", - sdp: "sdp1", - }, - offer_id: json.offer_id, - }; - tracker.processMessage(answerMessage, peer1); - }, - }; - let announceMessage: any = { - action: "announce", - event: "started", - info_hash: "swarm1", - peer_id: "1", - }; - tracker.processMessage(announceMessage, peer1); - - const peer2 = { - sendMessage: (json: any) => { - if (!json.offer) { - return; - } - const answerMessage = { - action: "announce", - info_hash: json.info_hash, - peer_id: "2", - to_peer_id: json.peer_id, - answer: { - type: "answer", - sdp: "sdp2", - }, - offer_id: json.offer_id, - }; - tracker.processMessage(answerMessage, peer2); - }, - }; - announceMessage = { - action: "announce", - event: "started", - info_hash: "swarm1", - peer_id: "2", - }; - tracker.processMessage(announceMessage, peer2); - - const peer3 = { - sendMessage: (json: any) => { - if (!json.offer) { - return; - } - const answerMessage = { - action: "announce", - info_hash: json.info_hash, - peer_id: "3", - to_peer_id: json.peer_id, - answer: { - type: "answer", - sdp: "sdp3", - }, - offer_id: json.offer_id, - }; - tracker.processMessage(answerMessage, peer3); - }, - }; - announceMessage = { - action: "announce", - event: "started", - info_hash: "swarm1", - peer_id: "3", - }; - tracker.processMessage(announceMessage, peer3); - - const mockedPeer0 = mock(PeerContextClass); - const peer0 = instance(mockedPeer0); - peer0.id = undefined; - peer0.swarm1 = undefined; - announceMessage = { - action: "announce", - event: "started", - info_hash: "swarm1", - peer_id: "0", - offers: [ - { - offer: { sdp: "sdp01" }, - offer_id: "1", - }, - { - offer: { sdp: "sdp02" }, - offer_id: "2", - }, - { - offer: { sdp: "sdp03" }, - offer_id: "3", - }, - ], - numwant: 100, - }; - tracker.processMessage(announceMessage, peer0); - - verify(mockedPeer0.sendMessage(anything(), peer0)).times(4); - - let [json] = capture(mockedPeer0.sendMessage).byCallIndex(1); - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm1"); - expect(json.peer_id).to.be.equal("1"); - expect(json.offer_id).to.be.equal("1"); - expect(json.answer.type).to.be.equal("answer"); - expect(json.answer.sdp).to.be.equal("sdp1"); - - [json] = capture(mockedPeer0.sendMessage).byCallIndex(2); - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm1"); - expect(json.peer_id).to.be.equal("2"); - expect(json.offer_id).to.be.equal("2"); - expect(json.answer.type).to.be.equal("answer"); - expect(json.answer.sdp).to.be.equal("sdp2"); - - [json] = capture(mockedPeer0.sendMessage).byCallIndex(3); - expect(json.action).to.be.equal("announce"); - expect(json.info_hash).to.be.equal("swarm1"); - expect(json.peer_id).to.be.equal("3"); - expect(json.offer_id).to.be.equal("3"); - expect(json.answer.type).to.be.equal("answer"); - expect(json.answer.sdp).to.be.equal("sdp3"); - }); }); diff --git a/test/memory/heap-usage.ts b/test/memory/heap-usage.ts index 9d10376..9886be1 100644 --- a/test/memory/heap-usage.ts +++ b/test/memory/heap-usage.ts @@ -15,7 +15,7 @@ */ import { FastTracker } from "../../lib/fast-tracker.js"; -import { PeerContext } from "../../lib/tracker.js"; +import { SocketContext } from "../../lib/tracker.js"; const peersCount = 100000; const swarmsCount = 1000000000; @@ -47,7 +47,7 @@ console.log( ); console.log("\nadding peers to swarms"); -const peers: PeerContext[] = []; +const peers: SocketContext[] = []; for (let p = 0; p < peersCount; p++) { message.peer_id = p.toPrecision(19).toString(); message.info_hash = Math.floor(swarmsCount * Math.random()) @@ -74,7 +74,7 @@ console.log( console.log("\nremoving peers"); for (const peer of peers) { - tracker.disconnectPeer(peer); + tracker.disconnectPeersFromSocket(peer); } peers.length = 0; diff --git a/test/simulation.test.ts b/test/simulation.test.ts index 200e40d..a511cdd 100644 --- a/test/simulation.test.ts +++ b/test/simulation.test.ts @@ -15,7 +15,7 @@ */ import { FastTracker } from "../lib/fast-tracker.js"; -import { PeerContext } from "../lib/tracker.js"; +import { SocketContext } from "../lib/tracker.js"; import { describe, it, expect } from "vitest"; describe("simulation", () => { @@ -28,12 +28,13 @@ describe("simulation", () => { const tracker = new FastTracker(); - const peers: PeerContext[] = []; + const peers: SocketContext[] = []; const peersData: Array<{ infoHash?: string; peerId: string }> = []; for (let i = 0; i < peersCount; i++) { peers.push({ - sendMessage: (json: any) => {}, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + sendMessage: (_json: object, _peer: SocketContext) => {}, }); peersData.push({ peerId: (i % Math.floor(peersCount * sameIdPeersRatio)).toString(), @@ -44,7 +45,7 @@ describe("simulation", () => { action: "announce", info_hash: "", peer_id: "", - offers: new Array(), + offers: new Array(), numwant: 100, }; @@ -70,7 +71,7 @@ describe("simulation", () => { action: "announce", event: "stopped", info_hash: peerData.infoHash, - peer_id: peer.id, + peer_id: peerData.peerId, }, peer, ); @@ -79,7 +80,7 @@ describe("simulation", () => { return; } else if (random < 0.06) { // disconnect - tracker.disconnectPeer(peer); + tracker.disconnectPeersFromSocket(peer); peerData.infoHash = undefined; peers[peerIndex] = { sendMessage: peer.sendMessage }; return; @@ -107,9 +108,12 @@ describe("simulation", () => { for (const [swarmId, swarm] of tracker.swarms) { expect(swarm.peers).to.be.not.empty; for (const peer of swarm.peers.values()) { - const peerData = peersData[peers.indexOf(peer)]; + const peerData = peersData.find( + (pd) => pd.peerId === peer.peerId && pd.infoHash === swarmId, + ); + expect(peerData).to.exist; - expect(peerData.infoHash).to.be.equal(swarmId); + expect(peerData?.infoHash).to.be.equal(swarmId); } } });