diff --git a/perf/impl/Makefile b/perf/impl/Makefile index c4d4f7e01..a29306410 100644 --- a/perf/impl/Makefile +++ b/perf/impl/Makefile @@ -1,39 +1,15 @@ -GO_SUBDIRS := $(wildcard go-libp2p/*/.) -RUST_SUBDIRS := $(wildcard rust-libp2p/*/.) -HTTPS_SUBDIRS := $(wildcard https/*/.) -QUIC_GO_SUBDIRS := $(wildcard quic-go/*/.) JS_SUBDIRS := $(wildcard js-libp2p/*/.) -all: $(RUST_SUBDIRS) $(GO_SUBDIRS) $(HTTPS_SUBDIRS) $(QUIC_GO_SUBDIRS) $(JS_SUBDIRS) - -$(RUST_SUBDIRS): - $(MAKE) -C $@ - -$(GO_SUBDIRS): - $(MAKE) -C $@ - -$(HTTPS_SUBDIRS): - $(MAKE) -C $@ - -$(QUIC_GO_SUBDIRS): - $(MAKE) -C $@ +all:$(JS_SUBDIRS) $(JS_SUBDIRS): $(MAKE) -C $@ -go-libp2p: $(GO_SUBDIRS) - -rust-libp2p: $(RUST_SUBDIRS) - -https: $(HTTPS_SUBDIRS) - -quic-go: $(QUIC_GO_SUBDIRS) - js-libp2p: $(JS_SUBDIRS) -clean: $(RUST_SUBDIRS:%=%clean) $(GO_SUBDIRS:%=%clean) $(HTTPS_SUBDIRS:%=%clean) $(QUIC_GO_SUBDIRS:%=%clean) $(JS_SUBDIRS:%=%clean) +clean: $(JS_SUBDIRS:%=%clean) %clean: $(MAKE) -C $* clean -.PHONY: $(RUST_SUBDIRS) $(GO_SUBDIRS) $(HTTPS_SUBDIRS) $(QUIC_GO_SUBDIRS) $(JS_SUBDIRS) all clean +.PHONY: $(JS_SUBDIRS) all clean diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/Makefile b/perf/impl/js-libp2p/v2.8-eventtarget/Makefile new file mode 100644 index 000000000..3405a22d2 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/Makefile @@ -0,0 +1,15 @@ +DOCKER_IMAGE := node:22-alpine +DOCKER_RUN := docker run --rm -v "$(shell pwd)":/usr/src/myapp -w /usr/src/myapp $(DOCKER_IMAGE) +DOCKER_RUN_LIBP2P := docker run --rm -v "$(shell pwd)/libp2p":/usr/src/myapp/libp2p -w /usr/src/myapp/libp2p $(DOCKER_IMAGE) + +all: perf + +perf: + $(DOCKER_RUN_LIBP2P) npm ci + $(DOCKER_RUN_LIBP2P) npm run build + $(DOCKER_RUN) npm ci + +clean: + rm -rf node_modules + +.PHONY: all clean perf diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/README.md new file mode 100644 index 000000000..41da9a5af --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/README.md @@ -0,0 +1,11 @@ +Server: + +``` +./perf --run-server --server-address 127.0.0.1:1234 --transport tcp +``` + +Client + +``` +./perf --server-address 127.0.0.1:1234 --transport tcp --upload-bytes 10000000 --download bytes=10000000 +``` \ No newline at end of file diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/index.js b/perf/impl/js-libp2p/v2.8-eventtarget/index.js new file mode 100644 index 000000000..464da9578 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/index.js @@ -0,0 +1,105 @@ +import { parseArgs } from 'node:util' +import { noise } from './libp2p/packages/connection-encrypter-noise/dist/src/index.js' +import { yamux } from './libp2p/packages/stream-multiplexer-yamux/dist/src/index.js' +import { perf } from './libp2p/packages/protocol-perf/dist/src/index.js' +import { tcp } from './libp2p/packages/transport-tcp/dist/src/index.js' +import { multiaddr } from '@multiformats/multiaddr' +import { createLibp2p } from './libp2p/packages/libp2p/dist/src/index.js' + +const argv = parseArgs({ + options: { + 'run-server': { + type: 'string', + default: 'false' + }, + 'server-address': { + type: 'string' + }, + transport: { + type: 'string', + default: 'tcp' + }, + 'upload-bytes': { + type: 'string', + default: '0' + }, + 'download-bytes': { + type: 'string', + default: '0' + } + } +}) + +/** + * @param {boolean} runServer + * @param {string} serverAddress + * @param {string} transport + * @param {number} uploadBytes + * @param {number} downloadBytes + */ +export async function main (runServer, serverAddress, transport, uploadBytes, downloadBytes) { + const { host, port } = splitHostPort(serverAddress) + + const config = { + transports: [ + tcp() + ], + streamMuxers: [ + yamux() + ], + connectionEncrypters: [ + noise() + ], + services: { + perf: perf() + } + } + + if (runServer) { + Object.assign(config, { + addresses: { + listen: [ + // #TODO: right now we only support tcp + `/ip4/${host}/tcp/${port}` + ] + } + }) + } + + const node = await createLibp2p(config) + + await node.start() + + if (!runServer) { + for await (const output of node.services.perf.measurePerformance(multiaddr(`/ip4/${host}/tcp/${port}`), uploadBytes, downloadBytes)) { + // eslint-disable-next-line no-console + console.log(JSON.stringify(output)) + } + + await node.stop() + } +} + +/** + * @param {string} address + * @returns { host: string, port?: string } + */ +function splitHostPort (address) { + try { + const parts = address.split(':') + const host = parts[0] + const port = parts[1] + return { + host, + port + } + } catch (error) { + throw Error('Invalid server address') + } +} + +main(argv.values['run-server'] === 'true', argv.values['server-address'], argv.values.transport, Number(argv.values['upload-bytes']), Number(argv.values['download-bytes'])).catch((err) => { + // eslint-disable-next-line no-console + console.error(err) + process.exit(1) +}) diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/package-lock.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/package-lock.json new file mode 100644 index 000000000..0c3358641 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/package-lock.json @@ -0,0 +1,28318 @@ +{ + "name": "js-libp2p-monorepo", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "js-libp2p-monorepo", + "version": "1.0.0", + "license": "Apache-2.0 OR MIT", + "workspaces": [ + "doc", + "interop", + "packages/*" + ], + "devDependencies": { + "aegir": "^47.0.6", + "npm-run-all": "^4.1.5" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@arr/every": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@arr/every/-/every-1.0.1.tgz", + "integrity": "sha512-UQFQ6SgyJ6LX42W8rHCs8KVc0JS0tzVL9ct4XYedJukskYVWTo49tNiMEK9C2HTyarbNiT/RVIRSY82vH+6sTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/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==", + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.1.tgz", + "integrity": "sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.27.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.1.tgz", + "integrity": "sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "regexpu-core": "^6.2.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", + "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-plugin-utils": "^7.27.1", + "debug": "^4.4.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.22.10" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.27.1.tgz", + "integrity": "sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", + "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-wrap-function": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", + "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.27.1", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.27.1.tgz", + "integrity": "sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.1", + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz", + "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-async-generator-functions instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-default-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.27.1.tgz", + "integrity": "sha512-hjlsMBl1aJc5lp8MoCDEZCiYzlgdRAShOjAfRw6X+GlpLpUPU7c3XNLsKFZbQk/1cRzBlJ7CXg3xJAJMrFa1Uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-nullish-coalescing-operator instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz", + "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.20.5", + "@babel/helper-compilation-targets": "^7.20.7", + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.20.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-catch-binding instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.21.0.tgz", + "integrity": "sha512-p4zeefM72gpmEe2fkUr/OnOXpWEf8nAgk7ZYVqqfFiyIG7oFfVZcCrU64hWn5xp4tQ9LkV4bTIa5rD0KANpKNA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-optional-chaining instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2", + "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-default-from": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.27.1.tgz", + "integrity": "sha512-eBC/3KSekshx19+N40MzjWqJd7KTEdOoLesAfa4IDFI8eRz5a47i5Oszus6zG/cwIXN63YhgLOMSSNJx49sENg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-flow": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.27.1.tgz", + "integrity": "sha512-p9OkPbZ5G7UT1MofwYFigGebnrzGJacoBSQM0/6bi/PUMVE+qlWDD/OalvQKbwgQzU6dl0xAv6r4X7Jme0RYxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", + "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", + "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz", + "integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", + "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.0.tgz", + "integrity": "sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.0.tgz", + "integrity": "sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-globals": "^7.28.0", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-replace-supers": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", + "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/template": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.0.tgz", + "integrity": "sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.28.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.27.1.tgz", + "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-flow-strip-types": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.27.1.tgz", + "integrity": "sha512-G5eDKsu50udECw7DL2AcsysXiQyB7Nfg521t2OAJ4tbfTJ27doHLeF/vlI1NZGlLdbb/v+ibvtL1YBQqYOwJGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-flow": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", + "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", + "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-compilation-targets": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/traverse": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", + "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", + "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-assign": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.27.1.tgz", + "integrity": "sha512-LP6tsnirA6iy13uBKiYgjJsfQrodmlSrpZModtlo1Vk8sOO68gfo7dfA9TGJyEgxTiO7czK4EGZm8FJEZtk4kQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.27.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", + "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-display-name": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", + "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", + "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.1", + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.28.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.1.tgz", + "integrity": "sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.28.0.tgz", + "integrity": "sha512-dGopk9nZrtCs2+nfIem25UuHyt5moSJamArzIoh9/vezUQPmYDOzjaHDCkAzuGJibCIkPup8rMT2+wYB6S73cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "babel-plugin-polyfill-corejs2": "^0.4.14", + "babel-plugin-polyfill-corejs3": "^0.13.0", + "babel-plugin-polyfill-regenerator": "^0.6.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", + "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", + "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", + "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", + "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.0.tgz", + "integrity": "sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", + "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.27.1", + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", + "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse--for-generate-function-map": { + "name": "@babel/traverse", + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@chainsafe/as-chacha20poly1305": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@chainsafe/as-chacha20poly1305/-/as-chacha20poly1305-0.1.0.tgz", + "integrity": "sha512-BpNcL8/lji/GM3+vZ/bgRWqJ1q5kwvTFmGPk7pxm/QQZDbaMI98waOHjEymTjq2JmdD/INdNBFOVSyJofXg7ew==", + "license": "Apache-2.0" + }, + "node_modules/@chainsafe/as-sha256": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@chainsafe/as-sha256/-/as-sha256-1.2.0.tgz", + "integrity": "sha512-H2BNHQ5C3RS+H0ZvOdovK6GjFAyq5T6LClad8ivwj9Oaiy28uvdsGVS7gNJKuZmg0FGHAI+n7F0Qju6U0QkKDA==", + "license": "Apache-2.0" + }, + "node_modules/@chainsafe/is-ip": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.1.0.tgz", + "integrity": "sha512-KIjt+6IfysQ4GCv66xihEitBjvhU/bixbbbFxdJ1sqCp4uJ0wuZiYBPhksZoy4lfaF0k9cwNzY5upEW/VWdw3w==", + "license": "MIT" + }, + "node_modules/@chainsafe/libp2p-noise": { + "resolved": "packages/connection-encrypter-noise", + "link": true + }, + "node_modules/@chainsafe/libp2p-yamux": { + "resolved": "packages/stream-multiplexer-yamux", + "link": true + }, + "node_modules/@chainsafe/netmask": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@chainsafe/netmask/-/netmask-2.0.0.tgz", + "integrity": "sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg==", + "license": "MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspell/cspell-bundled-dicts": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-9.2.0.tgz", + "integrity": "sha512-e4qb78SQWqHkRw47W8qFJ3RPijhSLkADF+T0oH8xl3r/golq1RGp2/KrWOqGRRofUSTiIKYqaMX7mbAyFnOxyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-ada": "^4.1.1", + "@cspell/dict-al": "^1.1.1", + "@cspell/dict-aws": "^4.0.12", + "@cspell/dict-bash": "^4.2.1", + "@cspell/dict-companies": "^3.2.2", + "@cspell/dict-cpp": "^6.0.9", + "@cspell/dict-cryptocurrencies": "^5.0.5", + "@cspell/dict-csharp": "^4.0.7", + "@cspell/dict-css": "^4.0.18", + "@cspell/dict-dart": "^2.3.1", + "@cspell/dict-data-science": "^2.0.9", + "@cspell/dict-django": "^4.1.5", + "@cspell/dict-docker": "^1.1.15", + "@cspell/dict-dotnet": "^5.0.10", + "@cspell/dict-elixir": "^4.0.8", + "@cspell/dict-en_us": "^4.4.15", + "@cspell/dict-en-common-misspellings": "^2.1.3", + "@cspell/dict-en-gb-mit": "^3.1.5", + "@cspell/dict-filetypes": "^3.0.13", + "@cspell/dict-flutter": "^1.1.1", + "@cspell/dict-fonts": "^4.0.5", + "@cspell/dict-fsharp": "^1.1.1", + "@cspell/dict-fullstack": "^3.2.7", + "@cspell/dict-gaming-terms": "^1.1.2", + "@cspell/dict-git": "^3.0.7", + "@cspell/dict-golang": "^6.0.23", + "@cspell/dict-google": "^1.0.9", + "@cspell/dict-haskell": "^4.0.6", + "@cspell/dict-html": "^4.0.12", + "@cspell/dict-html-symbol-entities": "^4.0.4", + "@cspell/dict-java": "^5.0.12", + "@cspell/dict-julia": "^1.1.1", + "@cspell/dict-k8s": "^1.0.12", + "@cspell/dict-kotlin": "^1.1.1", + "@cspell/dict-latex": "^4.0.4", + "@cspell/dict-lorem-ipsum": "^4.0.5", + "@cspell/dict-lua": "^4.0.8", + "@cspell/dict-makefile": "^1.0.5", + "@cspell/dict-markdown": "^2.0.12", + "@cspell/dict-monkeyc": "^1.0.11", + "@cspell/dict-node": "^5.0.8", + "@cspell/dict-npm": "^5.2.12", + "@cspell/dict-php": "^4.0.15", + "@cspell/dict-powershell": "^5.0.15", + "@cspell/dict-public-licenses": "^2.0.14", + "@cspell/dict-python": "^4.2.19", + "@cspell/dict-r": "^2.1.1", + "@cspell/dict-ruby": "^5.0.9", + "@cspell/dict-rust": "^4.0.12", + "@cspell/dict-scala": "^5.0.8", + "@cspell/dict-shell": "^1.1.1", + "@cspell/dict-software-terms": "^5.1.4", + "@cspell/dict-sql": "^2.2.1", + "@cspell/dict-svelte": "^1.0.7", + "@cspell/dict-swift": "^2.0.6", + "@cspell/dict-terraform": "^1.1.3", + "@cspell/dict-typescript": "^3.2.3", + "@cspell/dict-vue": "^3.0.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/cspell-json-reporter": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-9.2.0.tgz", + "integrity": "sha512-qHdkW8eyknCSDEsqCG8OHBMal03LQf21H2LVWhtwszEQ4BQRKcWctc+VIgkO69F/jLaN2wi/yhhMufXWHAEzIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "9.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/cspell-pipe": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-9.2.0.tgz", + "integrity": "sha512-RO3adcsr7Ek+4511nyEOWDhOYYU1ogRs1Mo5xx3kDIdcKAJzhFdGry35T2wqft4dPASLCXcemBrhoS+hdQ+z+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/cspell-resolver": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-9.2.0.tgz", + "integrity": "sha512-0Xvwq0iezfO71Alw+DjsGxacAzydqOAxdXnY4JknHuxt2l8GTSMjRwj65QAflv3PN6h1QoRZEeWdiKtusceWAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-directory": "^4.0.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/cspell-service-bus": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-9.2.0.tgz", + "integrity": "sha512-ZDvcOTFk3cCVW+OjlkljeP7aSuV8tIguVn+GMco1/A+961hsEP20hngK9zJtyfpXqyvJKtvCVlyzS+z8VRrZGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/cspell-types": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-9.2.0.tgz", + "integrity": "sha512-hL4ltFwiARpFxlfXt4GiTWQxIFyZp4wrlp7dozZbitYO6QlYc5fwQ8jBc5zFUqknuH4gx/sCMLNXhAv3enNGZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/dict-ada": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.1.tgz", + "integrity": "sha512-E+0YW9RhZod/9Qy2gxfNZiHJjCYFlCdI69br1eviQQWB8yOTJX0JHXLs79kOYhSW0kINPVUdvddEBe6Lu6CjGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-al": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.1.tgz", + "integrity": "sha512-sD8GCaZetgQL4+MaJLXqbzWcRjfKVp8x+px3HuCaaiATAAtvjwUQ5/Iubiqwfd1boIh2Y1/3EgM3TLQ7Q8e0wQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-aws": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.14.tgz", + "integrity": "sha512-qLPR+OFmpzyUcuUYyCQFIURDDUGIlQsdGirPyvaIrXxs2giCKG97cAuFz5EleL3/Lo7uJAVDw0lt4Ka7wIRhjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-bash": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.1.tgz", + "integrity": "sha512-SBnzfAyEAZLI9KFS7DUG6Xc1vDFuLllY3jz0WHvmxe8/4xV3ufFE3fGxalTikc1VVeZgZmxYiABw4iGxVldYEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-shell": "1.1.1" + } + }, + "node_modules/@cspell/dict-companies": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.2.3.tgz", + "integrity": "sha512-7ekwamRYeS7G3I3LEKM3t0WIyAytCbsx2I2h2z2eEvF+b3TmtJVcV7UI7BScLue3bep4sPB/b4CV3BUv3QfyzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cpp": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-6.0.9.tgz", + "integrity": "sha512-Xdq9MwGh0D5rsnbOqFW24NIClXXRhN11KJdySMibpcqYGeomxB2ODFBuhj1H7azO7kVGkGH0Okm4yQ2TRzBx0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cryptocurrencies": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.5.tgz", + "integrity": "sha512-R68hYYF/rtlE6T/dsObStzN5QZw+0aQBinAXuWCVqwdS7YZo0X33vGMfChkHaiCo3Z2+bkegqHlqxZF4TD3rUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-csharp": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.7.tgz", + "integrity": "sha512-H16Hpu8O/1/lgijFt2lOk4/nnldFtQ4t8QHbyqphqZZVE5aS4J/zD/WvduqnLY21aKhZS6jo/xF5PX9jyqPKUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-css": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.18.tgz", + "integrity": "sha512-EF77RqROHL+4LhMGW5NTeKqfUd/e4OOv6EDFQ/UQQiFyWuqkEKyEz0NDILxOFxWUEVdjT2GQ2cC7t12B6pESwg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dart": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.1.tgz", + "integrity": "sha512-xoiGnULEcWdodXI6EwVyqpZmpOoh8RA2Xk9BNdR7DLamV/QMvEYn8KJ7NlRiTSauJKPNkHHQ5EVHRM6sTS7jdg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-data-science": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.9.tgz", + "integrity": "sha512-wTOFMlxv06veIwKdXUwdGxrQcK44Zqs426m6JGgHIB/GqvieZQC5n0UI+tUm5OCxuNyo4OV6mylT4cRMjtKtWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-django": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.5.tgz", + "integrity": "sha512-AvTWu99doU3T8ifoMYOMLW2CXKvyKLukPh1auOPwFGHzueWYvBBN+OxF8wF7XwjTBMMeRleVdLh3aWCDEX/ZWg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-docker": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.16.tgz", + "integrity": "sha512-UiVQ5RmCg6j0qGIxrBnai3pIB+aYKL3zaJGvXk1O/ertTKJif9RZikKXCEgqhaCYMweM4fuLqWSVmw3hU164Iw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dotnet": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.10.tgz", + "integrity": "sha512-ooar8BP/RBNP1gzYfJPStKEmpWy4uv/7JCq6FOnJLeD1yyfG3d/LFMVMwiJo+XWz025cxtkM3wuaikBWzCqkmg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-elixir": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.8.tgz", + "integrity": "sha512-CyfphrbMyl4Ms55Vzuj+mNmd693HjBFr9hvU+B2YbFEZprE5AG+EXLYTMRWrXbpds4AuZcvN3deM2XVB80BN/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en_us": { + "version": "4.4.16", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.16.tgz", + "integrity": "sha512-/R47sUbUmba2dG/0LZyE6P6gX/DRF1sCcYNQNWyPk/KeidQRNZG+FH9U0KRvX42/2ZzMge6ebXH3WAJ52w0Vqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en-common-misspellings": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.1.3.tgz", + "integrity": "sha512-v1I97Hr1OrK+mwHsVzbY4vsPxx6mA5quhxzanF6XuRofz00wH4HPz8Q3llzRHxka5Wl/59gyan04UkUrvP4gdA==", + "dev": true, + "license": "CC BY-SA 4.0" + }, + "node_modules/@cspell/dict-en-gb-mit": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb-mit/-/dict-en-gb-mit-3.1.6.tgz", + "integrity": "sha512-3JJGxuPhDK5rMDYPzJYAdjjsBddEyV54rXfUQpOCl7c7weMhNDWfC2q4h3cKNDj7Isud1q2RM+DlSxQWf40OTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-filetypes": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.13.tgz", + "integrity": "sha512-g6rnytIpQlMNKGJT1JKzWkC+b3xCliDKpQ3ANFSq++MnR4GaLiifaC4JkVON11Oh/UTplYOR1nY3BR4X30bswA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-flutter": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.1.tgz", + "integrity": "sha512-UlOzRcH2tNbFhZmHJN48Za/2/MEdRHl2BMkCWZBYs+30b91mWvBfzaN4IJQU7dUZtowKayVIF9FzvLZtZokc5A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fonts": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.5.tgz", + "integrity": "sha512-BbpkX10DUX/xzHs6lb7yzDf/LPjwYIBJHJlUXSBXDtK/1HaeS+Wqol4Mlm2+NAgZ7ikIE5DQMViTgBUY3ezNoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fsharp": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.1.tgz", + "integrity": "sha512-imhs0u87wEA4/cYjgzS0tAyaJpwG7vwtC8UyMFbwpmtw+/bgss+osNfyqhYRyS/ehVCWL17Ewx2UPkexjKyaBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fullstack": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.7.tgz", + "integrity": "sha512-IxEk2YAwAJKYCUEgEeOg3QvTL4XLlyArJElFuMQevU1dPgHgzWElFevN5lsTFnvMFA1riYsVinqJJX0BanCFEg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-gaming-terms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.2.tgz", + "integrity": "sha512-9XnOvaoTBscq0xuD6KTEIkk9hhdfBkkvJAIsvw3JMcnp1214OCGW8+kako5RqQ2vTZR3Tnf3pc57o7VgkM0q1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-git": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.0.7.tgz", + "integrity": "sha512-odOwVKgfxCQfiSb+nblQZc4ErXmnWEnv8XwkaI4sNJ7cNmojnvogYVeMqkXPjvfrgEcizEEA4URRD2Ms5PDk1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-golang": { + "version": "6.0.23", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.23.tgz", + "integrity": "sha512-oXqUh/9dDwcmVlfUF5bn3fYFqbUzC46lXFQmi5emB0vYsyQXdNWsqi6/yH3uE7bdRE21nP7Yo0mR1jjFNyLamg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-google": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.9.tgz", + "integrity": "sha512-biL65POqialY0i4g6crj7pR6JnBkbsPovB2WDYkj3H4TuC/QXv7Pu5pdPxeUJA6TSCHI7T5twsO4VSVyRxD9CA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-haskell": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.6.tgz", + "integrity": "sha512-ib8SA5qgftExpYNjWhpYIgvDsZ/0wvKKxSP+kuSkkak520iPvTJumEpIE+qPcmJQo4NzdKMN8nEfaeci4OcFAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.12.tgz", + "integrity": "sha512-JFffQ1dDVEyJq6tCDWv0r/RqkdSnV43P2F/3jJ9rwLgdsOIXwQbXrz6QDlvQLVvNSnORH9KjDtenFTGDyzfCaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html-symbol-entities": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.4.tgz", + "integrity": "sha512-afea+0rGPDeOV9gdO06UW183Qg6wRhWVkgCFwiO3bDupAoyXRuvupbb5nUyqSTsLXIKL8u8uXQlJ9pkz07oVXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-java": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.12.tgz", + "integrity": "sha512-qPSNhTcl7LGJ5Qp6VN71H8zqvRQK04S08T67knMq9hTA8U7G1sTKzLmBaDOFhq17vNX/+rT+rbRYp+B5Nwza1A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-julia": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.1.tgz", + "integrity": "sha512-WylJR9TQ2cgwd5BWEOfdO3zvDB+L7kYFm0I9u0s9jKHWQ6yKmfKeMjU9oXxTBxIufhCXm92SKwwVNAC7gjv+yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-k8s": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.12.tgz", + "integrity": "sha512-2LcllTWgaTfYC7DmkMPOn9GsBWsA4DZdlun4po8s2ysTP7CPEnZc1ZfK6pZ2eI4TsZemlUQQ+NZxMe9/QutQxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-kotlin": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.1.tgz", + "integrity": "sha512-J3NzzfgmxRvEeOe3qUXnSJQCd38i/dpF9/t3quuWh6gXM+krsAXP75dY1CzDmS8mrJAlBdVBeAW5eAZTD8g86Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-latex": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-4.0.4.tgz", + "integrity": "sha512-YdTQhnTINEEm/LZgTzr9Voz4mzdOXH7YX+bSFs3hnkUHCUUtX/mhKgf1CFvZ0YNM2afjhQcmLaR9bDQVyYBvpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lorem-ipsum": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.5.tgz", + "integrity": "sha512-9a4TJYRcPWPBKkQAJ/whCu4uCAEgv/O2xAaZEI0n4y1/l18Yyx8pBKoIX5QuVXjjmKEkK7hi5SxyIsH7pFEK9Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lua": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.8.tgz", + "integrity": "sha512-N4PkgNDMu9JVsRu7JBS/3E/dvfItRgk9w5ga2dKq+JupP2Y3lojNaAVFhXISh4Y0a6qXDn2clA6nvnavQ/jjLA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-makefile": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.5.tgz", + "integrity": "sha512-4vrVt7bGiK8Rx98tfRbYo42Xo2IstJkAF4tLLDMNQLkQ86msDlYSKG1ZCk8Abg+EdNcFAjNhXIiNO+w4KflGAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-markdown": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.12.tgz", + "integrity": "sha512-ufwoliPijAgWkD/ivAMC+A9QD895xKiJRF/fwwknQb7kt7NozTLKFAOBtXGPJAB4UjhGBpYEJVo2elQ0FCAH9A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@cspell/dict-css": "^4.0.18", + "@cspell/dict-html": "^4.0.12", + "@cspell/dict-html-symbol-entities": "^4.0.4", + "@cspell/dict-typescript": "^3.2.3" + } + }, + "node_modules/@cspell/dict-monkeyc": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.11.tgz", + "integrity": "sha512-7Q1Ncu0urALI6dPTrEbSTd//UK0qjRBeaxhnm8uY5fgYNFYAG+u4gtnTIo59S6Bw5P++4H3DiIDYoQdY/lha8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-node": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.8.tgz", + "integrity": "sha512-AirZcN2i84ynev3p2/1NCPEhnNsHKMz9zciTngGoqpdItUb2bDt1nJBjwlsrFI78GZRph/VaqTVFwYikmncpXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-npm": { + "version": "5.2.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.13.tgz", + "integrity": "sha512-yE7DfpiQjDFW6TLr5/fsSj4BlUy1A8lsuz2LQQHv4lQAAkZ4RsePYFL9DkRRfEtxn8CZYetUnU74/jQbfsnyrA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-php": { + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.0.15.tgz", + "integrity": "sha512-iepGB2gtToMWSTvybesn4/lUp4LwXcEm0s8vasJLP76WWVkq1zYjmeS+WAIzNgsuURyZ/9mGqhS0CWMuo74ODw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-powershell": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.15.tgz", + "integrity": "sha512-l4S5PAcvCFcVDMJShrYD0X6Huv9dcsQPlsVsBGbH38wvuN7gS7+GxZFAjTNxDmTY1wrNi1cCatSg6Pu2BW4rgg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-public-licenses": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.14.tgz", + "integrity": "sha512-8NhNzQWALF6+NlLeKZKilSHbeW9MWeiD+NcrjehMAcovKFbsn8smmQG/bVxw+Ymtd6WEgNpLgswAqNsbSQQ4og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-python": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.19.tgz", + "integrity": "sha512-9S2gTlgILp1eb6OJcVZeC8/Od83N8EqBSg5WHVpx97eMMJhifOzePkE0kDYjyHMtAFznCQTUu0iQEJohNQ5B0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-data-science": "^2.0.9" + } + }, + "node_modules/@cspell/dict-r": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.1.tgz", + "integrity": "sha512-71Ka+yKfG4ZHEMEmDxc6+blFkeTTvgKbKAbwiwQAuKl3zpqs1Y0vUtwW2N4b3LgmSPhV3ODVY0y4m5ofqDuKMw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-ruby": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.0.9.tgz", + "integrity": "sha512-H2vMcERMcANvQshAdrVx0XoWaNX8zmmiQN11dZZTQAZaNJ0xatdJoSqY8C8uhEMW89bfgpN+NQgGuDXW2vmXEw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-rust": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.12.tgz", + "integrity": "sha512-z2QiH+q9UlNhobBJArvILRxV8Jz0pKIK7gqu4TgmEYyjiu1TvnGZ1tbYHeu9w3I/wOP6UMDoCBTty5AlYfW0mw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-scala": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.8.tgz", + "integrity": "sha512-YdftVmumv8IZq9zu1gn2U7A4bfM2yj9Vaupydotyjuc+EEZZSqAafTpvW/jKLWji2TgybM1L2IhmV0s/Iv9BTw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-shell": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.1.1.tgz", + "integrity": "sha512-T37oYxE7OV1x/1D4/13Y8JZGa1QgDCXV7AVt3HLXjn0Fe3TaNDvf5sU0fGnXKmBPqFFrHdpD3uutAQb1dlp15g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-software-terms": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.1.5.tgz", + "integrity": "sha512-MX5beBP3pLmIM0mjqfrHbie3EEfyLWZ8ZqW56jcLuRlLoDcfC0FZsr66NCARgCgEwsWiidHFe87+7fFsnwqY6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-sql": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.1.tgz", + "integrity": "sha512-qDHF8MpAYCf4pWU8NKbnVGzkoxMNrFqBHyG/dgrlic5EQiKANCLELYtGlX5auIMDLmTf1inA0eNtv74tyRJ/vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-svelte": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.7.tgz", + "integrity": "sha512-hGZsGqP0WdzKkdpeVLBivRuSNzOTvN036EBmpOwxH+FTY2DuUH7ecW+cSaMwOgmq5JFSdTcbTNFlNC8HN8lhaQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-swift": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.6.tgz", + "integrity": "sha512-PnpNbrIbex2aqU1kMgwEKvCzgbkHtj3dlFLPMqW1vSniop7YxaDTtvTUO4zA++ugYAEL+UK8vYrBwDPTjjvSnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-terraform": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.3.tgz", + "integrity": "sha512-gr6wxCydwSFyyBKhBA2xkENXtVFToheqYYGFvlMZXWjviynXmh+NK/JTvTCk/VHk3+lzbO9EEQKee6VjrAUSbA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-typescript": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.3.tgz", + "integrity": "sha512-zXh1wYsNljQZfWWdSPYwQhpwiuW0KPW1dSd8idjMRvSD0aSvWWHoWlrMsmZeRl4qM4QCEAjua8+cjflm41cQBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-vue": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.5.tgz", + "integrity": "sha512-Mqutb8jbM+kIcywuPQCCaK5qQHTdaByoEO2J9LKFy3sqAdiBogNkrplqUK0HyyRFgCfbJUgjz3N85iCMcWH0JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dynamic-import": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-9.2.0.tgz", + "integrity": "sha512-2/k4LR8CQqbgIPQGELbCdt9xgg9+aQ7pMwOtllKvnFYBtwNiwqcZjlzAam2gtvD5DghKX2qrcSHG5A7YP5cX9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "9.2.0", + "import-meta-resolve": "^4.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/filetypes": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-9.2.0.tgz", + "integrity": "sha512-6wmCa3ZyI647H7F4w6kb9PCJ703JKSgFTB8EERTdIoGySbgVp5+qMIIoZ//wELukdjgcufcFZ5pBrhRDRsemRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/strong-weak-map": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-9.2.0.tgz", + "integrity": "sha512-5mpIMiIOCu4cBqy1oCTXISgJuOCQ6R/e38AkvnYWfmMIx7fCdx8n+mF52wX9m61Ng28Sq8VL253xybsWcCxHug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspell/url": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@cspell/url/-/url-9.2.0.tgz", + "integrity": "sha512-plB0wwdAESqBl4xDAT2db2/K1FZHJXfYlJTiV6pkn0XffTGyg4UGLaSCm15NzUoPxdSmzqj5jQb7y+mB9kFK8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@electron/get": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-4.0.2.tgz", + "integrity": "sha512-n9fRt/nzzOOZdDtTP3kT6GVdo0ro9FgMKCoS520kQMIiKBhpGmPny6yK/lER3tOCKr+wLYW1O25D9oI6ZinwCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^3.0.0", + "got": "^14.4.5", + "graceful-fs": "^4.2.11", + "progress": "^2.0.3", + "semver": "^7.6.3", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=22.12.0" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz", + "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/core/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@emnapi/runtime": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz", + "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz", + "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.50.2", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.50.2.tgz", + "integrity": "sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6", + "@typescript-eslint/types": "^8.11.0", + "comment-parser": "1.4.1", + "esquery": "^1.6.0", + "jsdoc-type-pratt-parser": "~4.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", + "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz", + "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz", + "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz", + "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz", + "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz", + "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz", + "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz", + "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz", + "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz", + "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz", + "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz", + "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz", + "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz", + "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz", + "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz", + "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz", + "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz", + "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz", + "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz", + "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz", + "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz", + "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz", + "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz", + "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz", + "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz", + "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@gerrit0/mini-shiki": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.9.2.tgz", + "integrity": "sha512-Tvsj+AOO4Z8xLRJK900WkyfxHsZQu+Zm1//oT1w443PO6RiYMoq/4NGOhaNuZoUMYsjKIAPVQ6eOFMddj6yphQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-oniguruma": "^3.9.2", + "@shikijs/langs": "^3.9.2", + "@shikijs/themes": "^3.9.2", + "@shikijs/types": "^3.9.2", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/gitignore-to-minimatch": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz", + "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==", + "dev": true, + "license": "Apache-2.0", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@isaacs/balanced-match": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", + "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", + "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/balanced-match": "^4.0.1" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/create-cache-key-function": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz", + "integrity": "sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/@jest/transform/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==", + "license": "MIT" + }, + "node_modules/@jest/transform/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/@jest/transform/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.10.tgz", + "integrity": "sha512-0pPkgz9dY+bijgistcTTJ5mR+ocqRXLuhXHYdzoMmmoJ2C9S46RCm2GMUbatPEUK9Yjy26IrAy8D/M00lLkv+Q==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@libp2p/crypto": { + "resolved": "packages/crypto", + "link": true + }, + "node_modules/@libp2p/interface": { + "resolved": "packages/interface", + "link": true + }, + "node_modules/@libp2p/interface-internal": { + "resolved": "packages/interface-internal", + "link": true + }, + "node_modules/@libp2p/logger": { + "resolved": "packages/logger", + "link": true + }, + "node_modules/@libp2p/multistream-select": { + "resolved": "packages/multistream-select", + "link": true + }, + "node_modules/@libp2p/peer-collections": { + "resolved": "packages/peer-collections", + "link": true + }, + "node_modules/@libp2p/peer-id": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-5.1.8.tgz", + "integrity": "sha512-pGaM4BwjnXdGtAtd84L4/wuABpsnFYE+AQ+h3GxNFme0IsTaTVKWd1jBBE5YFeKHBHGUOhF3TlHsdjFfjQA7TA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "multiformats": "^13.3.6", + "uint8arrays": "^5.1.0" + } + }, + "node_modules/@libp2p/peer-record": { + "resolved": "packages/peer-record", + "link": true + }, + "node_modules/@libp2p/peer-store": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/@libp2p/peer-store/-/peer-store-11.2.6.tgz", + "integrity": "sha512-3Lc982/7drqlXa51s9l1/DFHD48zzIjMMYajxFM2KbobyStH+lztYnFc3kNGB9sZijULaW1480PvbTMm9WaJ0g==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "@libp2p/peer-collections": "^6.0.34", + "@libp2p/peer-id": "^5.1.8", + "@libp2p/peer-record": "^8.0.34", + "@multiformats/multiaddr": "^12.4.4", + "interface-datastore": "^8.3.1", + "it-all": "^3.0.8", + "main-event": "^1.0.1", + "mortice": "^3.2.1", + "multiformats": "^13.3.6", + "protons-runtime": "^5.5.0", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + } + }, + "node_modules/@libp2p/perf": { + "resolved": "packages/protocol-perf", + "link": true + }, + "node_modules/@libp2p/tcp": { + "resolved": "packages/transport-tcp", + "link": true + }, + "node_modules/@libp2p/utils": { + "resolved": "packages/utils", + "link": true + }, + "node_modules/@multiformats/dns": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@multiformats/dns/-/dns-1.0.6.tgz", + "integrity": "sha512-nt/5UqjMPtyvkG9BQYdJ4GfLK3nMqGpFZOzf4hAmIa0sJh2LlS9YKXZ4FgwBDsaHvzZqR/rUFIywIc7pkHNNuw==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@types/dns-packet": "^5.6.5", + "buffer": "^6.0.3", + "dns-packet": "^5.6.1", + "hashlru": "^2.3.0", + "p-queue": "^8.0.1", + "progress-events": "^1.0.0", + "uint8arrays": "^5.0.2" + } + }, + "node_modules/@multiformats/multiaddr": { + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", + "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@multiformats/dns": "^1.0.3", + "abort-error": "^1.0.1", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/@multiformats/multiaddr-matcher": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-2.0.2.tgz", + "integrity": "sha512-si7EZCI93mfBJKKRkh+u2bB9W6W5APVN3XfdwuseEJ0OS7ysg0Jno9SuAi0bRzsl5OEFESoF71SjsRqgp8PXAA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@multiformats/multiaddr": "^12.0.0" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", + "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.6", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.6.tgz", + "integrity": "sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nolyfill/is-core-module": { + "version": "1.0.39", + "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", + "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.4.0" + } + }, + "node_modules/@octokit/auth-token": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", + "integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/core": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-7.0.3.tgz", + "integrity": "sha512-oNXsh2ywth5aowwIa7RKtawnkdH6LgU1ztfP9AIUCQCvzysB+WeU8o2kyyosDPwBZutPpjZDKPQGIzzrfTWweQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/auth-token": "^6.0.0", + "@octokit/graphql": "^9.0.1", + "@octokit/request": "^10.0.2", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "before-after-hook": "^4.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/endpoint": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-11.0.0.tgz", + "integrity": "sha512-hoYicJZaqISMAI3JfaDr1qMNi48OctWuOih1m80bkYow/ayPw6Jj52tqWJ6GEoFTk1gBqfanSoI1iY99Z5+ekQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/graphql": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-9.0.1.tgz", + "integrity": "sha512-j1nQNU1ZxNFx2ZtKmL4sMrs4egy5h65OMDmSbVyuCzjOcwsHq6EaYjOTGXPQxgfiN8dJ4CriYHk6zF050WEULg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request": "^10.0.2", + "@octokit/types": "^14.0.0", + "universal-user-agent": "^7.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-25.1.0.tgz", + "integrity": "sha512-idsIggNXUKkk0+BExUn1dQ92sfysJrje03Q0bv0e+KPLrvyqZF8MnBpFz8UNfYDwB3Ie7Z0TByjWfzxt7vseaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-13.1.1.tgz", + "integrity": "sha512-q9iQGlZlxAVNRN2jDNskJW/Cafy7/XE52wjZ5TTvyhyOD904Cvx//DNyoO3J/MXJ0ve3rPoNWKEg5iZrisQSuw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.1.0" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=6" + } + }, + "node_modules/@octokit/plugin-retry": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-8.0.1.tgz", + "integrity": "sha512-KUoYR77BjF5O3zcwDQHRRZsUvJwepobeqiSSdCJ8lWt27FZExzb0GgVxrhhfuyF6z2B2zpO0hN5pteni1sqWiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": ">=7" + } + }, + "node_modules/@octokit/plugin-throttling": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-11.0.1.tgz", + "integrity": "sha512-S+EVhy52D/272L7up58dr3FNSMXWuNZolkL4zMJBNIfIxyZuUcczsQAU4b5w6dewJXnKYVgSHSV5wxitMSW1kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0", + "bottleneck": "^2.15.3" + }, + "engines": { + "node": ">= 20" + }, + "peerDependencies": { + "@octokit/core": "^7.0.0" + } + }, + "node_modules/@octokit/request": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-10.0.3.tgz", + "integrity": "sha512-V6jhKokg35vk098iBqp2FBKunk3kMTXlmq+PtbV9Gl3TfskWlebSofU9uunVKhUN7xl+0+i5vt0TGTG8/p/7HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/endpoint": "^11.0.0", + "@octokit/request-error": "^7.0.0", + "@octokit/types": "^14.0.0", + "fast-content-type-parse": "^3.0.0", + "universal-user-agent": "^7.0.2" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/request-error": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-7.0.0.tgz", + "integrity": "sha512-KRA7VTGdVyJlh0cP5Tf94hTiYVVqmt2f3I6mnimmaVz4UG3gQV/k4mDJlJv3X67iX6rmN7gSHCF8ssqeMnmhZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/types": "^14.0.0" + }, + "engines": { + "node": ">= 20" + } + }, + "node_modules/@octokit/types": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-14.1.0.tgz", + "integrity": "sha512-1y6DgTy8Jomcpu33N+p5w58l6xyt55Ar2I91RPiIA0xCJBXyUAhXCcmZaDWSANiha7R9a6qJJ2CRomGPZ6f46g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/openapi-types": "^25.1.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true, + "license": "ISC" + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.3.1.tgz", + "integrity": "sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@polka/send-type": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@polka/send-type/-/send-type-0.5.2.tgz", + "integrity": "sha512-jGXalKihnhGQmMQ+xxfxrRfI2cWs38TIZuwgYpnbQDD4r9TkOiU3ocjAS+6CqqMNQNAu9Ul2iHU5YFRDODak2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@polka/url": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-0.5.0.tgz", + "integrity": "sha512-oZLYFEAzUKyi3SKnXvj32ZCEGH6RDnao7COuCVhDydMS9NrCSVXhM79VaKyP5+Zc33m0QXEd2DN3UkU7OsHcfw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/assets-registry": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.80.2.tgz", + "integrity": "sha512-+sI2zIM22amhkZqW+RpD3qDoopeRiezrTtZMP+Y3HI+6/2JbEq7DdyV/2YS1lrSSdyy3STW2V37Lt4dKqP0lEQ==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.80.2.tgz", + "integrity": "sha512-eYad9ex9/RS6oFbbpu6LxsczktbhfJbJlTvtRlcWLJjJbFTeNr5Q7CgBT2/m5VtpxnJ/0YdmZ9vdazsJ2yp9kw==", + "license": "MIT", + "dependencies": { + "glob": "^7.1.1", + "hermes-parser": "0.28.1", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@react-native/codegen/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@react-native/codegen/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.80.2.tgz", + "integrity": "sha512-UBjsE+lv1YtThs56mgFaUdWv0jNE1oO58Lkbf3dn47F0e7YiTubIcvP6AnlaMhZF2Pmt9ky8J1jTpgItO9tGeg==", + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.80.2", + "chalk": "^4.0.0", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.82.2", + "metro-config": "^0.82.2", + "metro-core": "^0.82.2", + "semver": "^7.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@react-native-community/cli": "*" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + } + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.80.2.tgz", + "integrity": "sha512-n3D88bqNk0bY+YjNxbM6giqva06xj+rgEfu91Pg+nJ0szSL2eLl7ULERJqI3hxFt0XGuTpTOxZgw/Po5maXa4g==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.80.2.tgz", + "integrity": "sha512-8OeBEZNiApdbZaqTrrzeyFwXn/JwgJox7jdtjVAH56DggTVJXdbnyUjQ4ts6XAacEQgpFOAskoO730eyafOkAA==", + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.80.2", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^6.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.80.2.tgz", + "integrity": "sha512-C5/FYbIfCXPFjF/hIcWFKC9rEadDDhPMbxE7tarGR9tmYKyb9o7fYvfNe8fFgbCRKelMHP0ShATz3T73pHHDfA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.80.2.tgz", + "integrity": "sha512-f63M3paxHK92p6L9o+AY7hV/YojCZAhb+fdDpSfOtDtCngWbBhd6foJrO6IybzDFERxlwErupUg3pqr5w3KJWw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.80.2.tgz", + "integrity": "sha512-08Ax7554Z31NXi5SQ6h1GsiSrlZEOYHQNSC7u+x91Tdiq87IXldW8Ib1N3ThXoDcD8bjr+I+MdlabEJw36/fFg==", + "license": "MIT" + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.80.2.tgz", + "integrity": "sha512-kXsIV2eB73QClbbH/z/lRhZkyj3Dke4tarM5w2yXSNwJthMPMfj4KqLZ6Lnf0nmPPjz7qo/voKtlrGqlM822Rg==", + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/react": "^19.0.0", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@samverschueren/stream-to-observable": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@samverschueren/stream-to-observable/-/stream-to-observable-0.3.1.tgz", + "integrity": "sha512-c/qwwcHyafOQuVQJj0IlBjf5yYgBI7YPJ77k4fOJYesb41jio65eaJODRUmfYKhTOFBrIZ66kgvGPlNbjuoRdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-observable": "^0.3.0" + }, + "engines": { + "node": ">=6" + }, + "peerDependenciesMeta": { + "rxjs": { + "optional": true + }, + "zen-observable": { + "optional": true + } + } + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@semantic-release/changelog": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/changelog/-/changelog-6.0.3.tgz", + "integrity": "sha512-dZuR5qByyfe3Y03TpmCvAxCyTnp7r5XwtHRf/8vD9EAn4ZWbavUX8adMtXYzE86EVh0gyLA7lm5yW4IV30XUag==", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "fs-extra": "^11.0.0", + "lodash": "^4.17.4" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, + "node_modules/@semantic-release/commit-analyzer": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/commit-analyzer/-/commit-analyzer-13.0.1.tgz", + "integrity": "sha512-wdnBPHKkr9HhNhXOhZD5a2LNl91+hs8CC2vsAVYxtZH3y0dV3wKn+uZSN61rdJQZ8EGxzWB3inWocBHV9+u/CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/error": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@semantic-release/git": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", + "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, + "node_modules/@semantic-release/git/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@semantic-release/git/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/git/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/@semantic-release/git/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/git/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@semantic-release/git/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@semantic-release/git/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/git/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/@semantic-release/git/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@semantic-release/github": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.3.tgz", + "integrity": "sha512-T2fKUyFkHHkUNa5XNmcsEcDPuG23hwBKptfUVcFXDVG2cSjXXZYDOfVYwfouqbWo/8UefotLaoGfQeK+k3ep6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@octokit/core": "^7.0.0", + "@octokit/plugin-paginate-rest": "^13.0.0", + "@octokit/plugin-retry": "^8.0.0", + "@octokit/plugin-throttling": "^11.0.0", + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "debug": "^4.3.4", + "dir-glob": "^3.0.1", + "globby": "^14.0.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "issue-parser": "^7.0.0", + "lodash-es": "^4.17.21", + "mime": "^4.0.0", + "p-filter": "^4.0.0", + "url-join": "^5.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=24.1.0" + } + }, + "node_modules/@semantic-release/github/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/github/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/github/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-12.0.2.tgz", + "integrity": "sha512-+M9/Lb35IgnlUO6OSJ40Ie+hUsZLuph2fqXC/qrKn0fMvUU/jiCjpoL6zEm69vzcmaZJ8yNKtMBEKHWN49WBbQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^4.0.0", + "aggregate-error": "^5.0.0", + "execa": "^9.0.0", + "fs-extra": "^11.0.0", + "lodash-es": "^4.17.21", + "nerf-dart": "^1.0.0", + "normalize-url": "^8.0.0", + "npm": "^10.9.3", + "rc": "^1.2.8", + "read-pkg": "^9.0.0", + "registry-auth-token": "^5.0.0", + "semver": "^7.1.2", + "tempy": "^3.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@semantic-release/npm/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@semantic-release/npm/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/npm/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@semantic-release/release-notes-generator": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/@semantic-release/release-notes-generator/-/release-notes-generator-14.0.3.tgz", + "integrity": "sha512-XxAZRPWGwO5JwJtS83bRdoIhCiYIx8Vhr+u231pQAsdFIAbm19rSVJLdnBN+Avvk7CKvNQE/nJ4y7uqKH6WTiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-changelog-angular": "^8.0.0", + "conventional-changelog-writer": "^8.0.0", + "conventional-commits-filter": "^5.0.0", + "conventional-commits-parser": "^6.0.0", + "debug": "^4.0.0", + "get-stream": "^7.0.0", + "import-from-esm": "^2.0.0", + "into-stream": "^7.0.0", + "lodash-es": "^4.17.21", + "read-package-up": "^11.0.0" + }, + "engines": { + "node": ">=20.8.1" + }, + "peerDependencies": { + "semantic-release": ">=20.1.0" + } + }, + "node_modules/@shikijs/engine-oniguruma": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.9.2.tgz", + "integrity": "sha512-Vn/w5oyQ6TUgTVDIC/BrpXwIlfK6V6kGWDVVz2eRkF2v13YoENUvaNwxMsQU/t6oCuZKzqp9vqtEtEzKl9VegA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.9.2", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@shikijs/langs": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.9.2.tgz", + "integrity": "sha512-X1Q6wRRQXY7HqAuX3I8WjMscjeGjqXCg/Sve7J2GWFORXkSrXud23UECqTBIdCSNKJioFtmUGJQNKtlMMZMn0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.9.2" + } + }, + "node_modules/@shikijs/themes": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.9.2.tgz", + "integrity": "sha512-6z5lBPBMRfLyyEsgf6uJDHPa6NAGVzFJqH4EAZ+03+7sedYir2yJBRu2uPZOKmj43GyhVHWHvyduLDAwJQfDjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.9.2" + } + }, + "node_modules/@shikijs/types": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.9.2.tgz", + "integrity": "sha512-/M5L0Uc2ljyn2jKvj4Yiah7ow/W+DJSglVafvWAJ/b8AZDeeRAdMu3c2riDzB7N42VD+jSnWxeP9AKtd4TfYVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, + "node_modules/@shikijs/vscode-textmate": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "license": "MIT" + }, + "node_modules/@sindresorhus/fnv1a": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/fnv1a/-/fnv1a-3.1.0.tgz", + "integrity": "sha512-KV321z5m/0nuAg83W1dPLy85HpHDk7Sdi4fJbwvacWsEhAh+rZUW4ZfGcXmUIvjZg4ss2bcwNlRhJ7GBEUG08w==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sindresorhus/is": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-7.0.2.tgz", + "integrity": "sha512-d9xRovfKNz1SKieM0qJdO+PQonjnnIfSNWfHYnBSJ9hkjm0ZPw6HlxscDXYstp3z+7V2GOFHc+J0CYrYTjqCJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/commons/node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.11.0.tgz", + "integrity": "sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.13.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "estraverse": "^5.3.0", + "picomatch": "^4.0.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz", + "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tybys/wasm-util/node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/chai": { + "version": "4.3.20", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", + "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai-as-promised": { + "version": "7.1.8", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", + "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/chai-string": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/@types/chai-string/-/chai-string-1.4.5.tgz", + "integrity": "sha512-IecXRMSnpUvRnTztdpSdjcmcW7EdNme65bfDCQMi7XrSEPGmyDYYTEfc5fcactWDA6ioSm8o7NUqg9QxjBCCEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/chai-subset": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.6.tgz", + "integrity": "sha512-m8lERkkQj+uek18hXOZuec3W/fCRTrU4hrnXjH3qhHy96ytuPaPiWGgu7sJb7tZxZonO75vYAjCvpe/e4VUwRw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/chai": "<5.2.0" + } + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/dns-packet": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/@types/dns-packet/-/dns-packet-5.6.5.tgz", + "integrity": "sha512-qXOC7XLOEe43ehtWJCMnQXvgcIpv6rPmQ1jXT98Ad8A3TB1Ue50jsCbSSSyuazScEuZ/Q026vHbrOTVkmwA+7Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", + "dev": true, + "license": "MIT" + }, + "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==", + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "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, + "license": "MIT" + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mdast": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/netmask": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@types/netmask/-/netmask-2.0.5.tgz", + "integrity": "sha512-9Q5iw9+pHZBVLDG700dlQSWWHTYvOb8KfPjfQTNckCYky4IyjV2xh81+RgC1CCwqv92bYLpz1cVKyJav0B88uQ==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.17.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.0.tgz", + "integrity": "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==", + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/react-native": { + "version": "0.73.0", + "resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.73.0.tgz", + "integrity": "sha512-6ZRPQrYM72qYKGWidEttRe6M5DZBEV5F+MHMHqd4TTYx0tfkcdrUFGdef6CCxY0jXU7wldvd/zA/b0A/kTeJmA==", + "deprecated": "This is a stub types definition. react-native provides its own type definitions, so you do not need this installed.", + "license": "MIT", + "dependencies": { + "react-native": "*" + } + }, + "node_modules/@types/retry": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.2.tgz", + "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", + "license": "MIT" + }, + "node_modules/@types/sinon": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-17.0.4.tgz", + "integrity": "sha512-RHnIrhfPO3+tJT0s7cFaXGZvsL4bbR3/k7z3P312qMS4JaS2Tk+KiwiLx1S0rQ56ERj00u1/BtdyVd0FY+Pdew==", + "license": "MIT", + "dependencies": { + "@types/sinonjs__fake-timers": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", + "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", + "license": "MIT" + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "license": "MIT" + }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/unist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yargs": { + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.0.tgz", + "integrity": "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/type-utils": "8.39.0", + "@typescript-eslint/utils": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.39.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.0.tgz", + "integrity": "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.0.tgz", + "integrity": "sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.39.0", + "@typescript-eslint/types": "^8.39.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.0.tgz", + "integrity": "sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.0.tgz", + "integrity": "sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.0.tgz", + "integrity": "sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/utils": "8.39.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.0.tgz", + "integrity": "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.0.tgz", + "integrity": "sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.39.0", + "@typescript-eslint/tsconfig-utils": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/visitor-keys": "8.39.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.0.tgz", + "integrity": "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.39.0", + "@typescript-eslint/types": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz", + "integrity": "sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.39.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@unrs/resolver-binding-android-arm-eabi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz", + "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-android-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz", + "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-arm64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz", + "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-darwin-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz", + "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@unrs/resolver-binding-freebsd-x64": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz", + "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz", + "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz", + "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz", + "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-arm64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz", + "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz", + "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz", + "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz", + "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz", + "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-gnu": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz", + "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-linux-x64-musl": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz", + "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@unrs/resolver-binding-wasm32-wasi": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz", + "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^0.2.11" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz", + "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz", + "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@unrs/resolver-binding-win32-x64-msvc": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz", + "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.18.tgz", + "integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@vue/shared": "3.5.18", + "entities": "^4.5.0", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz", + "integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.18", + "@vue/shared": "3.5.18" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz", + "integrity": "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@vue/compiler-core": "3.5.18", + "@vue/compiler-dom": "3.5.18", + "@vue/compiler-ssr": "3.5.18", + "@vue/shared": "3.5.18", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.17", + "postcss": "^8.5.6", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz", + "integrity": "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.18", + "@vue/shared": "3.5.18" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.18", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz", + "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/abort-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/abort-error/-/abort-error-1.0.1.tgz", + "integrity": "sha512-fxqCblJiIPdSXIUrxI0PL+eJG49QdP9SQ70qtB65MVAoMr2rASlOyAbJFOylfB467F/f+5BCLJJq58RYi7mGfg==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-loose": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-8.5.2.tgz", + "integrity": "sha512-PPvV6g8UGMGgjrMu+n/f9E/tCSkNQ2Y97eFvuVdJfG11+xdIeDcLyNdC8SHcrHbRqkfwLASdplyR6B6sKM1U4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aegir": { + "version": "47.0.21", + "resolved": "https://registry.npmjs.org/aegir/-/aegir-47.0.21.tgz", + "integrity": "sha512-PcMzkLOfQbuBMq9W5T5uyRosY78xpAMvOc163/fwMncHJEQqigSTJSs4erhMdpLljDQUiL5Nl5/pp3RUUPLj2Q==", + "dev": true, + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@electron/get": "^4.0.0", + "@polka/send-type": "^0.5.2", + "@semantic-release/changelog": "^6.0.1", + "@semantic-release/commit-analyzer": "^13.0.0", + "@semantic-release/git": "^10.0.1", + "@semantic-release/github": "^11.0.0", + "@semantic-release/npm": "^12.0.0", + "@semantic-release/release-notes-generator": "^14.0.0", + "@types/chai": "^4.2.16", + "@types/chai-as-promised": "^7.1.3", + "@types/chai-string": "^1.4.2", + "@types/chai-subset": "^1.3.3", + "@types/mocha": "^10.0.0", + "@types/node": "^22.10.7", + "@typescript-eslint/parser": "^8.32.1", + "buffer": "^6.0.3", + "bytes": "^3.1.0", + "c8": "^10.1.2", + "chai": "^4.3.4", + "chai-as-promised": "^7.1.1", + "chai-bites": "^0.1.2", + "chai-parentheses": "^0.0.2", + "chai-string": "^1.5.0", + "chai-subset": "^1.6.0", + "conventional-changelog-conventionalcommits": "^8.0.0", + "cors": "^2.8.5", + "cspell": "^9.0.1", + "depcheck": "^1.4.3", + "diff": "^8.0.1", + "electron-mocha": "^13.0.0", + "env-paths": "^3.0.0", + "esbuild": "^0.25.0", + "eslint": "^9.27.0", + "eslint-formatter-unix": "^8.40.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.6.17", + "eslint-plugin-no-only-tests": "^3.3.0", + "execa": "^9.5.3", + "extract-zip": "^2.0.1", + "fast-glob": "^3.3.2", + "fs-extra": "^11.1.0", + "gh-pages": "^6.0.0", + "globby": "^14.0.0", + "is-plain-obj": "^4.1.0", + "kleur": "^4.1.4", + "latest-version": "^9.0.0", + "lilconfig": "^3.0.0", + "listr": "~0.14.2", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm": "^3.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-extension-gfm": "^3.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.1", + "mocha": "^11.0.1", + "neostandard": "^0.12.1", + "npm-package-json-lint": "^8.0.0", + "nyc": "^17.0.0", + "p-map": "^7.0.1", + "p-queue": "^8.0.1", + "p-retry": "^6.0.0", + "pascalcase": "^2.0.0", + "path": "^0.12.7", + "playwright-test": "^14.0.0", + "polka": "^0.5.2", + "prompt": "^1.2.2", + "proper-lockfile": "^4.1.2", + "react-native-test-runner": "^5.0.0", + "read-pkg-up": "^11.0.0", + "rimraf": "^6.0.1", + "semantic-release": "^24.0.0", + "semantic-release-monorepo": "^8.0.2", + "semver": "^7.3.8", + "source-map-support": "^0.5.20", + "strip-bom": "^5.0.0", + "strip-json-comments": "^5.0.0", + "strong-log-transformer": "^2.1.0", + "tempy": "^3.1.0", + "typedoc": "^0.28.4", + "typedoc-plugin-mdn-links": "^5.0.2", + "typedoc-plugin-mermaid": "^1.12.0", + "typedoc-plugin-missing-exports": "^4.0.0", + "typescript": "5.8.3", + "typescript-docs-verifier": "^2.5.0", + "wherearewe": "^2.0.1", + "yargs": "^17.1.1", + "yargs-parser": "^21.1.1" + }, + "bin": { + "aegir": "src/index.js" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "license": "MIT" + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-observable": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.3.0.tgz", + "integrity": "sha512-/FQM1EDkTsf63Ub2C6O7GuYFDsSXUwsaZDurV0np41ocwq0jthUAYCmhBX9f+KwlaCgIuWyr/4WlUQUBfKfZog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/any-signal": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/any-signal/-/any-signal-4.1.1.tgz", + "integrity": "sha512-iADenERppdC+A2YKbOXXB2WUeABLaM6qnpZ70kZbPZ1cZMMJ7eF+3CaYm+/PhBizgkzlvssC7QuHS30oOiQYWA==", + "license": "Apache-2.0 OR MIT", + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true, + "license": "MIT" + }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argv-formatter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/argv-formatter/-/argv-formatter-1.0.0.tgz", + "integrity": "sha512-F2+Hkm9xFaRg+GkaNnbwXNDV5O6pnCFEmqyhvfC/Ic5LbgOWjJh3L+mN/s91rxVL3znE7DYVpW0GJFT+4YBgWw==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array-ify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", + "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-includes": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", + "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.24.0", + "es-object-atoms": "^1.1.1", + "get-intrinsic": "^1.3.0", + "is-string": "^1.1.1", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz", + "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-shim-unscopables": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", + "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", + "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", + "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/assert/node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/babel-jest/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", + "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.7", + "@babel/helper-define-polyfill-provider": "^0.6.5", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", + "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5", + "core-js-compat": "^3.43.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", + "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.6.5" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.28.1.tgz", + "integrity": "sha512-meT17DOuUElMNsL5LZN56d+KBp22hb0EfxWfuPUeoSi54e40v1W4C2V36P75FpsH9fVEfDKpw5Nnkahc8haSsQ==", + "license": "MIT", + "dependencies": { + "hermes-parser": "0.28.1" + } + }, + "node_modules/babel-plugin-transform-inline-environment-variables": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-environment-variables/-/babel-plugin-transform-inline-environment-variables-0.4.4.tgz", + "integrity": "sha512-bJILBtn5a11SmtR2j/3mBOjX4K3weC6cq+NNZ7hG22wCAqpc3qtj/iN7dSe9HDiS46lgp1nHsQgeYrea/RUe+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz", + "integrity": "sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==", + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" + }, + "peerDependencies": { + "@babel/core": "^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/before-after-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-4.0.0.tgz", + "integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/bottleneck": { + "version": "2.19.5", + "resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz", + "integrity": "sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/c8": { + "version": "10.1.3", + "resolved": "https://registry.npmjs.org/c8/-/c8-10.1.3.tgz", + "integrity": "sha512-LvcyrOAaOnrrlMpW22n690PUvxiq4Uf9WMhQwNJ9vgagkL/ph1+D4uvjvDA5XCbykrc0sx+ay6pVi9YZ1GnhyA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.1", + "@istanbuljs/schema": "^0.1.3", + "find-up": "^5.0.0", + "foreground-child": "^3.1.1", + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.1.6", + "test-exclude": "^7.0.1", + "v8-to-istanbul": "^9.0.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "c8": "bin/c8.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "monocart-coverage-reports": "^2" + }, + "peerDependenciesMeta": { + "monocart-coverage-reports": { + "optional": true + } + } + }, + "node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/cacheable-request": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-12.0.1.tgz", + "integrity": "sha512-Yo9wGIQUaAfIbk+qY0X4cDQgCosecfBe3V9NSyeY4qPC2SAkbCS4Xj79VP8WOzitpJUZKc/wsRCYF5ariDIwkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "^4.0.4", + "get-stream": "^9.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.4", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.1", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha512-JuG3qI4QOftFsZyOn1qq87fq5grLIyk1JYd5lJmdA+fG7aQ9pA/i3JIJGcO3q0MrRcHlOt1U+ZeHW8Dq9axALQ==", + "license": "MIT", + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-callsite/node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha512-ksWePWBloaWPxJYQ8TL0JHvtci6G5QTKwQ95RcWAa/lzoAKuAOflGdAK92hpHXjkwb8zLxoLNUoNYZgVsaJzvQ==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha512-MCL3sf6nCSXOwCTzvPKhN18TU7AHTvdtam8DAogxcrJ8Rjfbbg7Lgng64H9Iy+vUV6VGFClN/TyxBkAebLRR4A==", + "license": "MIT", + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys/node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chai": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chai-as-promised": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", + "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "check-error": "^1.0.2" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, + "node_modules/chai-bites": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/chai-bites/-/chai-bites-0.1.2.tgz", + "integrity": "sha512-eZVKGTywFkRuMle/UkiT9OXU4y4WeNy0yKe2t5iclIW3Yn9X3l7iWZoSeTjTpeQ1SIMn3In0rctjVCaRuKCmng==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "chai": ">=2 <5" + } + }, + "node_modules/chai-parentheses": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/chai-parentheses/-/chai-parentheses-0.0.2.tgz", + "integrity": "sha512-pdBOsH31vzWKYHr8JYTlsP+TFx7RTTm/2hQYbpxFd1WQ/X58ryrLBINRL2C1OWje8bi42NQqNZl2RooFPrsBqA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chai-string": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/chai-string/-/chai-string-1.6.0.tgz", + "integrity": "sha512-sXV7whDmpax+8H++YaZelgin7aur1LGf9ZhjZa3ojETFJ0uPVuS4XEXuIagpZ/c8uVOtsSh4MwOjy5CBLjJSXA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "chai": "^4.1.2" + } + }, + "node_modules/chai-subset": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/chai-subset/-/chai-subset-1.6.0.tgz", + "integrity": "sha512-K3d+KmqdS5XKW5DWPd5sgNffL3uxdDe+6GdnJh3AYPhwnBGRY5urfvfcbRtWIvvpz+KxkL9FeBB6MZewLUNwug==", + "deprecated": "functionality of this lib is built-in to chai now. see more details here: https://github.com/debitoor/chai-subset/pull/85", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.5.0.tgz", + "integrity": "sha512-1tm8DTaJhPBG3bIkVeZt1iZM9GfSX2lzOeDVZH9R9ffRHpmHvxZ/QhgQH/aDTkswQVt+YHdXAdS/In/30OjCbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk-template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-1.1.0.tgz", + "integrity": "sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chokidar/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", + "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "node_modules/chromium-edge-launcher/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/chromium-edge-launcher/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/chromium-edge-launcher/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chromium-edge-launcher/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT" + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha512-8lgKz8LmCRYZZQDpRyT2m5rKJ08TnU4tR9FFFW2rxpxR1FzWi4PQ/NfyODchAatHaUgnSPVcx/R5w6NuTBzFiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-highlight": { + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", + "integrity": "sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg==", + "dev": true, + "license": "ISC", + "dependencies": { + "chalk": "^4.0.0", + "highlight.js": "^10.7.1", + "mz": "^2.4.0", + "parse5": "^5.1.1", + "parse5-htmlparser2-tree-adapter": "^6.0.0", + "yargs": "^16.0.0" + }, + "bin": { + "highlight": "bin/highlight" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0" + } + }, + "node_modules/cli-highlight/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cli-highlight/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/cli-highlight/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-highlight/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/cli-highlight/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-highlight/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.5.tgz", + "integrity": "sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-table3/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-table3/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", + "integrity": "sha512-f4r4yJnbT++qUPI9NR4XLDLq41gQ+uqnPItWG0F5ZkehuNiTTa3EY0S4AqTSUOeJ7/zU41oWPQSNkW5BqPL9bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "slice-ansi": "0.0.4", + "string-width": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha512-pFGrxThWcWQ2MsAz6RtgeWe4NK2kUE1WfsrvvlctdII745EW9I0yflqhe7++M5LEc7bV2c/9/5zc8sFcpL0Drw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/comment-json": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/compare-func": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", + "integrity": "sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-ify": "^1.0.0", + "dot-prop": "^5.1.0" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/conventional-changelog-angular": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-8.0.0.tgz", + "integrity": "sha512-CLf+zr6St0wIxos4bmaKHRXWAcsCXrJU6F4VdNDrGRK3B8LDLKoX3zuMV5GhtbGkVR/LohZ6MT6im43vZLSjmA==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-conventionalcommits": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-conventionalcommits/-/conventional-changelog-conventionalcommits-8.0.0.tgz", + "integrity": "sha512-eOvlTO6OcySPyyyk8pKz2dP4jjElYunj9hn9/s0OB+gapTO8zwS9UQWrZ1pmF2hFs3vw1xhonOLGcGjy/zgsuA==", + "dev": true, + "license": "ISC", + "dependencies": { + "compare-func": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-changelog-writer": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.2.0.tgz", + "integrity": "sha512-Y2aW4596l9AEvFJRwFGJGiQjt2sBYTjPD18DdvxX9Vpz0Z7HQ+g1Z+6iYDAm1vR3QOJrDBkRHixHK/+FhkR6Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "conventional-commits-filter": "^5.0.0", + "handlebars": "^4.7.7", + "meow": "^13.0.0", + "semver": "^7.5.2" + }, + "bin": { + "conventional-changelog-writer": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-filter": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-5.0.0.tgz", + "integrity": "sha512-tQMagCOC59EVgNZcC5zl7XqO30Wki9i9J3acbUvkaosCT6JX3EeFwJD7Qqp4MCikRnzS18WXV3BLIQ66ytu6+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/conventional-commits-parser": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.2.0.tgz", + "integrity": "sha512-uLnoLeIW4XaoFtH37qEcg/SXMJmKF4vi7V0H2rnPueg+VEtFGA/asSCNTcq4M/GQ6QmlzchAEtOoDTtKqWeHag==", + "dev": true, + "license": "MIT", + "dependencies": { + "meow": "^13.0.0" + }, + "bin": { + "conventional-commits-parser": "dist/cli/index.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/convert-hrtime": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/convert-hrtime/-/convert-hrtime-5.0.0.tgz", + "integrity": "sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/copy-file": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-file/-/copy-file-11.0.0.tgz", + "integrity": "sha512-mFsNh/DIANLqFt5VHZoGirdg7bK5+oTWlhnGu6tgRhzBlnEKWaPX2xrFaLltii/6rmhqFMJqffUgknuRdpYlHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.11", + "p-event": "^6.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js-compat": { + "version": "3.45.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.45.0.tgz", + "integrity": "sha512-gRoVMBawZg0OnxaVv3zpqLLxaHmsubEGyTnqdpI/CEBvX4JadI1dMSHxagThprYRtSVbuQxvi6iUatdPxohHpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.25.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/cpy": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/cpy/-/cpy-11.1.0.tgz", + "integrity": "sha512-QGHetPSSuprVs+lJmMDcivvrBwTKASzXQ5qxFvRC2RFESjjod71bDvFvhxTjDgkNjrrb72AI6JPjfYwxrIy33A==", + "dev": true, + "license": "MIT", + "dependencies": { + "copy-file": "^11.0.0", + "globby": "^14.0.2", + "junk": "^4.0.1", + "micromatch": "^4.0.7", + "p-filter": "^4.1.0", + "p-map": "^7.0.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cspell": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-9.2.0.tgz", + "integrity": "sha512-AKzaFMem2jRcGpAY2spKP0z15jpZeX1WTDNHCDsB8/YvnhnOfWXc0S5AF+4sfU1cQgHWYGFOolMuTri0ZQdV+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-json-reporter": "9.2.0", + "@cspell/cspell-pipe": "9.2.0", + "@cspell/cspell-types": "9.2.0", + "@cspell/dynamic-import": "9.2.0", + "@cspell/url": "9.2.0", + "chalk": "^5.4.1", + "chalk-template": "^1.1.0", + "commander": "^14.0.0", + "cspell-config-lib": "9.2.0", + "cspell-dictionary": "9.2.0", + "cspell-gitignore": "9.2.0", + "cspell-glob": "9.2.0", + "cspell-io": "9.2.0", + "cspell-lib": "9.2.0", + "fast-json-stable-stringify": "^2.1.0", + "flatted": "^3.3.3", + "semver": "^7.7.2", + "tinyglobby": "^0.2.14" + }, + "bin": { + "cspell": "bin.mjs", + "cspell-esm": "bin.mjs" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/streetsidesoftware/cspell?sponsor=1" + } + }, + "node_modules/cspell-config-lib": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-9.2.0.tgz", + "integrity": "sha512-Yc8+hT+uIWWCi6WMhOL6HDYbBCP2qig1tgKGThHVeOx6GviieV10TZ5kQ+P7ONgoqw2nmm7uXIC19dGYx3DblQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "9.2.0", + "comment-json": "^4.2.5", + "smol-toml": "^1.4.1", + "yaml": "^2.8.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cspell-dictionary": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-9.2.0.tgz", + "integrity": "sha512-lV4VtjsDtxu8LyCcb6DY7Br4e/Aw1xfR8QvjYhHaJ8t03xry9STey5Rkfp+lz+hlVevNcn3lfCaacGuXyD+lLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "9.2.0", + "@cspell/cspell-types": "9.2.0", + "cspell-trie-lib": "9.2.0", + "fast-equals": "^5.2.2" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cspell-gitignore": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-9.2.0.tgz", + "integrity": "sha512-gXDQZ7czTPwmEg1qtsUIjVEFm9IfgTO8rA02O8eYIveqjFixbSV3fIYOgoxZSZYxjt3O44m8+/zAFC1RE4CM/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "9.2.0", + "cspell-glob": "9.2.0", + "cspell-io": "9.2.0" + }, + "bin": { + "cspell-gitignore": "bin.mjs" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cspell-glob": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-9.2.0.tgz", + "integrity": "sha512-viycZDyegzW2AKPFqvX5RveqTrB0sKgexlCu2A8z8eumpYYor5sD1NP05VDOqkAF4hDuiGqkHn6iNo0L1wNgLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "9.2.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cspell-grammar": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-9.2.0.tgz", + "integrity": "sha512-qthAmWcNHpYAmufy7YWVg9xwrYANkVlI40bgC2uGd8EnKssm/qOPhqXXNS+kLf+q0NmJM5nMgRLhCC23xSp3JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "9.2.0", + "@cspell/cspell-types": "9.2.0" + }, + "bin": { + "cspell-grammar": "bin.mjs" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cspell-io": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-9.2.0.tgz", + "integrity": "sha512-oxKiqFLcz629FmOId8UpdDznpMvCgpuktg4nkD2G9pYpRh+fRLZpP4QtZPyvJqvpUIzFhIOznMeHjsiBYHOZUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-service-bus": "9.2.0", + "@cspell/url": "9.2.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cspell-lib": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-9.2.0.tgz", + "integrity": "sha512-RnhDIsETw6Ex0UaK3PFoJ2FwWMWfJPtdpNpv1qgmJwoGD4CzwtIqPOLtZ24zqdCP8ZnNTF/lwV/9rZVqifYjsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-bundled-dicts": "9.2.0", + "@cspell/cspell-pipe": "9.2.0", + "@cspell/cspell-resolver": "9.2.0", + "@cspell/cspell-types": "9.2.0", + "@cspell/dynamic-import": "9.2.0", + "@cspell/filetypes": "9.2.0", + "@cspell/strong-weak-map": "9.2.0", + "@cspell/url": "9.2.0", + "clear-module": "^4.1.2", + "comment-json": "^4.2.5", + "cspell-config-lib": "9.2.0", + "cspell-dictionary": "9.2.0", + "cspell-glob": "9.2.0", + "cspell-grammar": "9.2.0", + "cspell-io": "9.2.0", + "cspell-trie-lib": "9.2.0", + "env-paths": "^3.0.0", + "fast-equals": "^5.2.2", + "gensequence": "^7.0.0", + "import-fresh": "^3.3.1", + "resolve-from": "^5.0.0", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-uri": "^3.1.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cspell-trie-lib": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-9.2.0.tgz", + "integrity": "sha512-6GHL1KvLQzcPBSNY6QWOabq8YwRJAnNKamA0O/tRKy+11Hy99ysD4xvfu3kKYPAcobp5ZykX4nudHxy8yrEvng==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "9.2.0", + "@cspell/cspell-types": "9.2.0", + "gensequence": "^7.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cycle": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz", + "integrity": "sha512-TVF6svNzeQCOpjCqsy0/CSy8VgObG3wXusJ73xW2GbG5rGx7lC8zxDSURicsXI2UsGdi2L0QNRCi745/wUDvsA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/datastore-core": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-10.0.4.tgz", + "integrity": "sha512-IctgCO0GA7GHG7aRm3JRruibCsfvN4EXNnNIlLCZMKIv0TPkdAL5UFV3/xTYFYrrZ1jRNrXZNZRvfcVf/R+rAw==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/logger": "^5.1.18", + "interface-datastore": "^8.0.0", + "interface-store": "^6.0.0", + "it-drain": "^3.0.9", + "it-filter": "^3.1.3", + "it-map": "^3.1.3", + "it-merge": "^3.0.11", + "it-pipe": "^3.0.1", + "it-sort": "^3.0.8", + "it-take": "^3.0.8" + } + }, + "node_modules/date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true, + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", + "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.2.0.tgz", + "integrity": "sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-eql": { + "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, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/default-require-extensions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", + "integrity": "sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "strip-bom": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-require-extensions/node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/del": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "dev": true, + "license": "MIT", + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/del/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/del/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/del/node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/del/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/delay": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-6.0.0.tgz", + "integrity": "sha512-2NJozoOHQ4NuZuVIr5CWd0iiLVIRSDepakaovIN+9eIDHEhdCAEvSy2cuf1DCrPPQLvHmbqTHODlhHg8UCy4zw==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depcheck": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/depcheck/-/depcheck-1.4.7.tgz", + "integrity": "sha512-1lklS/bV5chOxwNKA/2XUUk/hPORp8zihZsXflr8x0kLwmcZ9Y9BsS6Hs3ssvA+2wUVbG0U2Ciqvm1SokNjPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.23.0", + "@babel/traverse": "^7.23.2", + "@vue/compiler-sfc": "^3.3.4", + "callsite": "^1.0.0", + "camelcase": "^6.3.0", + "cosmiconfig": "^7.1.0", + "debug": "^4.3.4", + "deps-regex": "^0.2.0", + "findup-sync": "^5.0.0", + "ignore": "^5.2.4", + "is-core-module": "^2.12.0", + "js-yaml": "^3.14.1", + "json5": "^2.2.3", + "lodash": "^4.17.21", + "minimatch": "^7.4.6", + "multimatch": "^5.0.0", + "please-upgrade-node": "^3.2.0", + "readdirp": "^3.6.0", + "require-package-name": "^2.0.1", + "resolve": "^1.22.3", + "resolve-from": "^5.0.0", + "semver": "^7.5.4", + "yargs": "^16.2.0" + }, + "bin": { + "depcheck": "bin/depcheck.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/depcheck/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/depcheck/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/depcheck/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/depcheck/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/depcheck/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/depcheck/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/depcheck/node_modules/minimatch": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.6.tgz", + "integrity": "sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/depcheck/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/depcheck/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/depcheck/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/depcheck/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/depcheck/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/deps-regex": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/deps-regex/-/deps-regex-0.2.0.tgz", + "integrity": "sha512-PwuBojGMQAYbWkMXOY9Pd/NWCDNHVH12pnS7WHqZkTSeMESe4hwnKKRp0yR87g37113x4JPbo/oIvXY+s/f56Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/diff": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz", + "integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true, + "license": "MIT" + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-mocha": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/electron-mocha/-/electron-mocha-13.1.0.tgz", + "integrity": "sha512-n/PxV2Jv3mGiqFwoYWvzsjBxNXzuLqkfgxeJtjrrLpuYN/9VaJP98FUsd4GRKFFerD3Q1KihqNCaLXXEER2j1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "electron-window": "^0.8.0", + "mocha": "^11.0.1", + "which": "^5.0.0", + "yargs": "^17.7.2" + }, + "bin": { + "electron-mocha": "bin/electron-mocha" + }, + "engines": { + "node": ">= 16.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.197", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.197.tgz", + "integrity": "sha512-m1xWB3g7vJ6asIFz+2pBUbq3uGmfmln1M9SSvBe4QIFWYrRHylP73zL/3nMjDmwz8V+1xAXQDfBd6+HPW0WvDQ==", + "license": "ISC" + }, + "node_modules/electron-window": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/electron-window/-/electron-window-0.8.1.tgz", + "integrity": "sha512-W1i9LfnZJozk3MXE8VgsL2E5wOUHSgyCvcg1H2vQQjj+gqhO9lVudgY3z3SF7LJAmi+0vy3CJkbMqsynWB49EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-electron-renderer": "^2.0.0" + } + }, + "node_modules/elegant-spinner": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz", + "integrity": "sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.3", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", + "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-ci": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.1.1.tgz", + "integrity": "sha512-mT3ks8F0kwpo7SYNds6nWj0PaRh+qJxIeBVBXAKTN9hphAzZv7s0QAZQbqnB1fAv/r4pJUGE15BV9UrS31FP2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^8.0.0", + "java-properties": "^1.0.2" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/env-ci/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/env-ci/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/env-ci/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/npm-run-path": { + "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, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-ci/node_modules/strip-final-newline": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "dependencies": { + "stackframe": "^1.3.4" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", + "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.6", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "iterator.prototype": "^1.1.4", + "safe-array-concat": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", + "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.8", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", + "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.8", + "@esbuild/android-arm": "0.25.8", + "@esbuild/android-arm64": "0.25.8", + "@esbuild/android-x64": "0.25.8", + "@esbuild/darwin-arm64": "0.25.8", + "@esbuild/darwin-x64": "0.25.8", + "@esbuild/freebsd-arm64": "0.25.8", + "@esbuild/freebsd-x64": "0.25.8", + "@esbuild/linux-arm": "0.25.8", + "@esbuild/linux-arm64": "0.25.8", + "@esbuild/linux-ia32": "0.25.8", + "@esbuild/linux-loong64": "0.25.8", + "@esbuild/linux-mips64el": "0.25.8", + "@esbuild/linux-ppc64": "0.25.8", + "@esbuild/linux-riscv64": "0.25.8", + "@esbuild/linux-s390x": "0.25.8", + "@esbuild/linux-x64": "0.25.8", + "@esbuild/netbsd-arm64": "0.25.8", + "@esbuild/netbsd-x64": "0.25.8", + "@esbuild/openbsd-arm64": "0.25.8", + "@esbuild/openbsd-x64": "0.25.8", + "@esbuild/openharmony-arm64": "0.25.8", + "@esbuild/sunos-x64": "0.25.8", + "@esbuild/win32-arm64": "0.25.8", + "@esbuild/win32-ia32": "0.25.8", + "@esbuild/win32-x64": "0.25.8" + } + }, + "node_modules/esbuild-plugin-wasm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/esbuild-plugin-wasm/-/esbuild-plugin-wasm-1.1.0.tgz", + "integrity": "sha512-0bQ6+1tUbySSnxzn5jnXHMDvYnT0cN/Wd4Syk8g/sqAIJUg7buTIi22svS3Qz6ssx895NT+TgLPb33xi1OkZig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "individual", + "url": "https://ko-fi.com/tschrock" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.5.1.tgz", + "integrity": "sha512-3z3vFexKIEnjHE3zCMRo6fn/e44U7T1khUjg+Hp0ZQMCigh28rALD0nPFBcGZuiLC5rLZa2ubQHDRln09JfU2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-formatter-unix": { + "version": "8.40.0", + "resolved": "https://registry.npmjs.org/eslint-formatter-unix/-/eslint-formatter-unix-8.40.0.tgz", + "integrity": "sha512-gfsmFZ/cb1MobrMfYl2IPFLZEz2tWQVO/tnmziNQdhWJMN85GfZD64dcPsEgaEoeVKgAtK6W9LWLlOxhJWZvDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint-import-context": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", + "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-tsconfig": "^4.10.1", + "stable-hash-x": "^0.2.0" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-context" + }, + "peerDependencies": { + "unrs-resolver": "^1.0.0" + }, + "peerDependenciesMeta": { + "unrs-resolver": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", + "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@nolyfill/is-core-module": "1.0.39", + "debug": "^4.4.0", + "get-tsconfig": "^4.10.0", + "is-bun-module": "^2.0.0", + "stable-hash": "^0.0.5", + "tinyglobby": "^0.2.13", + "unrs-resolver": "^1.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-import-resolver-typescript" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*", + "eslint-plugin-import-x": "*" + }, + "peerDependenciesMeta": { + "eslint-plugin-import": { + "optional": true + }, + "eslint-plugin-import-x": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz", + "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", + "integrity": "sha512-7Ds8+wAAoV3T+LAKeu39Y5BzXCrGKrcISfgKEqTS4BDN8SFEDQd0S43jiQ8vIa3wUKD07qitZdfzlenSi8/0qQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/ota-meshi", + "https://opencollective.com/eslint" + ], + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.11.0", + "eslint-compat-utils": "^0.5.1" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.32.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz", + "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rtsao/scc": "^1.1.0", + "array-includes": "^3.1.9", + "array.prototype.findlastindex": "^1.2.6", + "array.prototype.flat": "^1.3.3", + "array.prototype.flatmap": "^1.3.3", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.12.1", + "hasown": "^2.0.2", + "is-core-module": "^2.16.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "object.groupby": "^1.0.3", + "object.values": "^1.2.1", + "semver": "^6.3.1", + "string.prototype.trimend": "^1.0.9", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-import-x": { + "version": "4.16.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.16.1.tgz", + "integrity": "sha512-vPZZsiOKaBAIATpFE2uMI4w5IRwdv/FpQ+qZZMR4E+PeOcM4OeoEbqxRMnywdxP19TyB/3h6QBB0EWon7letSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "^8.35.0", + "comment-parser": "^1.4.1", + "debug": "^4.4.1", + "eslint-import-context": "^0.1.9", + "is-glob": "^4.0.3", + "minimatch": "^9.0.3 || ^10.0.1", + "semver": "^7.7.2", + "stable-hash-x": "^0.2.0", + "unrs-resolver": "^1.9.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-import-x" + }, + "peerDependencies": { + "@typescript-eslint/utils": "^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", + "eslint-import-resolver-node": "*" + }, + "peerDependenciesMeta": { + "@typescript-eslint/utils": { + "optional": true + }, + "eslint-import-resolver-node": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsdoc": { + "version": "50.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-50.8.0.tgz", + "integrity": "sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@es-joy/jsdoccomment": "~0.50.2", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.4.1", + "escape-string-regexp": "^4.0.0", + "espree": "^10.3.0", + "esquery": "^1.6.0", + "parse-imports-exports": "^0.2.4", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-n": { + "version": "17.21.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.21.3.tgz", + "integrity": "sha512-MtxYjDZhMQgsWRm/4xYLL0i2EhusWT7itDxlJ80l1NND2AL2Vi5Mvneqv/ikG9+zpran0VsVRXTEHrpLmUZRNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "globrex": "^0.1.2", + "ignore": "^5.3.2", + "semver": "^7.6.3", + "ts-declaration-location": "^1.0.6" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": ">=8.23.0" + } + }, + "node_modules/eslint-plugin-n/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-plugin-no-only-tests": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.3.0.tgz", + "integrity": "sha512-brcKcxGnISN2CcVhXJ/kEQlNa0MEfGRtwKtWA16SkqXHKitaKIMrfemJKLKX1YqDU5C/5JY3PvZXd5jEW04e0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=5.0.0" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.2.1.tgz", + "integrity": "sha512-SWKjd+EuvWkYaS+uN2csvj0KoP43YTu7+phKQ5v+xw6+A0gutVX2yqCeCkC3uLCJFiPfR2dD8Es5L7yUsmvEaA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.37.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", + "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.8", + "array.prototype.findlast": "^1.2.5", + "array.prototype.flatmap": "^1.3.3", + "array.prototype.tosorted": "^1.1.4", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.2.1", + "estraverse": "^5.3.0", + "hasown": "^2.0.2", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.9", + "object.fromentries": "^2.0.8", + "object.values": "^1.2.1", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.12", + "string.prototype.repeat": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" + } + }, + "node_modules/eslint-plugin-react/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-react/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/execa": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz", + "integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exit-hook": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-4.0.0.tgz", + "integrity": "sha512-Fqs7ChZm72y40wKjOFXBKg7nJZvQJmewP5/7LtePDdnah/+FH9Hp5sgMujSCMPXlxOAW2//1jrW9pnsY7o20vQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", + "integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==", + "license": "Apache-2.0" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "dev": true, + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-content-type-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz", + "integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-equals": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", + "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/file-url": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/file-url/-/file-url-3.0.0.tgz", + "integrity": "sha512-g872QGsHexznxkIAdK8UiZRe7SkE6kvylShU4Nsj8NvfvZag7S0QuQ4IgvPDkk75HxgjIVDwycFTDAgIiO4nDA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up-simple": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.1.tgz", + "integrity": "sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-versions": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-6.0.0.tgz", + "integrity": "sha512-2kCCtc+JvcZ86IGAz3Z2Y0A1baIz9fL31pH/0S1IqZr9Iwnjq8izfPtrCyQKO6TLMPELLsQMre7VDqeIKCsHkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver-regex": "^4.0.5", + "super-regex": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, + "node_modules/findup-sync": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", + "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.3", + "micromatch": "^4.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data-encoder": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.1.0.tgz", + "integrity": "sha512-G6NsmEW15s0Uw9XnCg+33H3ViYRyiM0hMrMhhqQOR8NFc5GhYrI+6I3u7OTw7b91J2g8rtvMBZJDbcGb2YUniw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha512-OMcX/4IC/uqEPVgGeyfN22LJk6AZrMkRZHxcHBMBvHScDGgwTm2GT2Wkgtocyd3JfZffjj2kYUDXXII0Fk9W0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/fs-extra": { + "version": "11.3.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.1.tgz", + "integrity": "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function-timeout": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/function-timeout/-/function-timeout-1.0.2.tgz", + "integrity": "sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensequence": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-7.0.0.tgz", + "integrity": "sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-7.0.1.tgz", + "integrity": "sha512-3M8C1EOFN6r8AMUhwUAACIoXZJEOufDU5+0gFFN5uNs6XYOralD2Pqkl7m046va6x77FwposWXbAhPPIOus7mQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.1.tgz", + "integrity": "sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/gh-pages": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.3.0.tgz", + "integrity": "sha512-Ot5lU6jK0Eb+sszG8pciXdjMXdBJ5wODvgjR+imihTqsUWF2K6dJ9HST55lgqcs8wWcw6o6wAsUzfcYRhJPXbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.4", + "commander": "^13.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^11.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gh-pages/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/gh-pages/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gh-pages/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/git-log-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/git-log-parser/-/git-log-parser-1.2.1.tgz", + "integrity": "sha512-PI+sPDvHXNPl5WNOErAK05s3j0lgwUzMN6o8cyQrDaKfT3qd7TmNJKeXX+SknI5I0QhG5fVPAEwSY4tRGDtYoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "argv-formatter": "~1.0.0", + "spawn-error-forwarder": "~1.0.0", + "split2": "~1.0.0", + "stream-combiner2": "~1.1.1", + "through2": "~2.0.0", + "traverse": "0.6.8" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/globby/node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/got": { + "version": "14.4.7", + "resolved": "https://registry.npmjs.org/got/-/got-14.4.7.tgz", + "integrity": "sha512-DI8zV1231tqiGzOiOzQWDhsBmncFW7oQDH6Zgy6pDPrqJuVZMtoSgPLLsBZQj8Jg4JFfwoOsDA8NGtLQLnIx2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^7.0.1", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^12.0.1", + "decompress-response": "^6.0.0", + "form-data-encoder": "^4.0.2", + "http2-wrapper": "^2.2.1", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^4.0.1", + "responselike": "^3.0.0", + "type-fest": "^4.26.1" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hasha/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/hashlru": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz", + "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hermes-estree": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.28.1.tgz", + "integrity": "sha512-w3nxl/RGM7LBae0v8LH2o36+8VqwOZGv9rX1wyoWT6YaKZLqpJZ0YQ5P0LVr3tuRpf7vCx0iIG4i/VmBJejxTQ==", + "license": "MIT" + }, + "node_modules/hermes-parser": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.28.1.tgz", + "integrity": "sha512-nf8o+hE8g7UJWParnccljHumE9Vlq8F7MqIdeahl+4x0tvCUJYRrT0L7h0MMg/X9YJmkNwsfbaNNrzPtFXOscg==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.28.1" + } + }, + "node_modules/highlight.js": { + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz", + "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": "*" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hook-std": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hook-std/-/hook-std-3.0.0.tgz", + "integrity": "sha512-jHRQzjSDzMtFy34AGj1DN+vq54WVuhSvKgrHf0OMiFQTwDD4L/qqofVEWjLOBMTn5+lCD3fPg32W9yOfnEJTTw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "license": "MIT", + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from-esm": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-from-esm/-/import-from-esm-2.0.0.tgz", + "integrity": "sha512-YVt14UZCgsX1vZQ3gKjkWVdBdHQ6eu3MPU1TBgL1H5orXe2+jWD006WCPPtOuwlQm10NuzOW5WawiF1Q9veW8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "import-meta-resolve": "^4.0.0" + }, + "engines": { + "node": ">=18.20" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/index-to-position": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.1.0.tgz", + "integrity": "sha512-XPdx9Dq4t9Qk1mTMbWONJqU7boCoumEH7fRET37HX5+khDUl3J2W6PdALxhILYlIYx2amlwYcRPp28p0tSiojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/interface-datastore": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-8.3.2.tgz", + "integrity": "sha512-R3NLts7pRbJKc3qFdQf+u40hK8XWc0w4Qkx3OFEstC80VoaDUABY/dXA2EJPhtNC+bsrf41Ehvqb6+pnIclyRA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "interface-store": "^6.0.0", + "uint8arrays": "^5.1.0" + } + }, + "node_modules/interface-store": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-6.0.3.tgz", + "integrity": "sha512-+WvfEZnFUhRwFxgz+QCQi7UC6o9AM0EHM9bpIe2Nhqb100NHCsTvNAn4eJgvgV2/tmLo1MP9nGxQKEcZTAueLA==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/into-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", + "integrity": "sha512-2dYz766i9HprMBasCMvHMuazJ7u4WzhJwo5kb3iPSiW/iRYV6uPari3zHoqZlnuaR7V1bEiNMxikhp37rdBXbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "from2": "^2.3.0", + "p-is-promise": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/irregular-plurals": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz", + "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bun-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", + "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.7.1" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha512-yVChGzahRFvbkscn2MlwGismPO12i9+znNruC5gVEntG3qu0xQMzsGg/JFbrsqDOHtHFPci+V5aP5T9I+yeKqw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-electron": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-electron/-/is-electron-2.2.2.tgz", + "integrity": "sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==", + "license": "MIT" + }, + "node_modules/is-electron-renderer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-electron-renderer/-/is-electron-renderer-2.0.1.tgz", + "integrity": "sha512-pRlQnpaCFhDVPtkXkP+g9Ybv/CjbiQDjnKFQTEjpBfDKeV6dRDBczuFRDpM6DVfk2EjpMS8t5kwE5jPnqYl3zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-loopback-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-loopback-addr/-/is-loopback-addr-2.0.2.tgz", + "integrity": "sha512-26POf2KRCno/KTNL5Q0b/9TYnL00xEsSaLfiFRmjM7m7Lw7ZMmFybzzuX4CcsLAluZGd+niLUiMRxEooVE3aqg==", + "license": "MIT" + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-1.1.0.tgz", + "integrity": "sha512-NqCa4Sa2d+u7BWc6CukaObG3Fh+CU9bvixbpcXYhy2VvYS7vVGIdAgnIS5Ks3A/cqk4rebLJ9s8zBstT2aKnIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "symbol-observable": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-uuid": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-uuid/-/is-uuid-1.0.2.tgz", + "integrity": "sha512-tCByphFcJgf2qmiMo5hMCgNAquNSagOetVetDvBXswGkNfoyEMvGH1yDlF8cbZbKnbVBr4Y5/rlpMz9umxyBkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/issue-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/issue-parser/-/issue-parser-7.0.1.tgz", + "integrity": "sha512-3YZcUUR2Wt1WsapF+S/WiA2WmlW0cWAoPccMqne7AxEBhCdFeTPjfv/Axb8V2gyCgY3nRw+ksZ3xSUX+R47iAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.capitalize": "^4.2.1", + "lodash.escaperegexp": "^4.1.2", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.uniqby": "^4.7.0" + }, + "engines": { + "node": "^18.17 || >=20.6.1" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "append-transform": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-processinfo": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz", + "integrity": "sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==", + "dev": true, + "license": "ISC", + "dependencies": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.3", + "istanbul-lib-coverage": "^3.2.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-processinfo/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/it-all": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/it-all/-/it-all-3.0.9.tgz", + "integrity": "sha512-fz1oJJ36ciGnu2LntAlE6SA97bFZpW7Rnt0uEc1yazzR2nKokZLr8lIRtgnpex4NsmaBcvHF+Z9krljWFy/mmg==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/it-byte-stream": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/it-byte-stream/-/it-byte-stream-2.0.3.tgz", + "integrity": "sha512-h7FFcn4DWiWsJw1dCJhuPdiY8cGi1z8g4aLAfFspTaJbwQxvEMlEBFG/f8lIVGwM8YK26ClM4/9lxLVhF33b8g==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "abort-error": "^1.0.1", + "it-queueless-pushable": "^2.0.0", + "it-stream-types": "^2.0.2", + "race-signal": "^1.1.3", + "uint8arraylist": "^2.4.8" + } + }, + "node_modules/it-drain": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/it-drain/-/it-drain-3.0.10.tgz", + "integrity": "sha512-0w/bXzudlyKIyD1+rl0xUKTI7k4cshcS43LTlBiGFxI8K1eyLydNPxGcsVLsFVtKh1/ieS8AnVWt6KwmozxyEA==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/it-filter": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/it-filter/-/it-filter-3.1.4.tgz", + "integrity": "sha512-80kWEKgiFEa4fEYD3mwf2uygo1dTQ5Y5midKtL89iXyjinruA/sNXl6iFkTcdNedydjvIsFhWLiqRPQP4fAwWQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-peekable": "^3.0.0" + } + }, + "node_modules/it-length-prefixed": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/it-length-prefixed/-/it-length-prefixed-10.0.1.tgz", + "integrity": "sha512-BhyluvGps26u9a7eQIpOI1YN7mFgi8lFwmiPi07whewbBARKAG9LE09Odc8s1Wtbt2MB6rNUrl7j9vvfXTJwdQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-reader": "^6.0.1", + "it-stream-types": "^2.0.1", + "uint8-varint": "^2.0.1", + "uint8arraylist": "^2.0.0", + "uint8arrays": "^5.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-length-prefixed-stream": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/it-length-prefixed-stream/-/it-length-prefixed-stream-2.0.3.tgz", + "integrity": "sha512-Ns3jNFy2mcFnV59llCYitJnFHapg8wIcOsWkEaAwOkG9v4HBCk24nze/zGDQjiJdDTyFXTT5GOY3M/uaksot3w==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "abort-error": "^1.0.1", + "it-byte-stream": "^2.0.0", + "it-stream-types": "^2.0.2", + "uint8-varint": "^2.0.4", + "uint8arraylist": "^2.4.8" + } + }, + "node_modules/it-map": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/it-map/-/it-map-3.1.4.tgz", + "integrity": "sha512-QB9PYQdE9fUfpVFYfSxBIyvKynUCgblb143c+ktTK6ZuKSKkp7iH58uYFzagqcJ5HcqIfn1xbfaralHWam+3fg==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-peekable": "^3.0.0" + } + }, + "node_modules/it-merge": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-3.0.12.tgz", + "integrity": "sha512-nnnFSUxKlkZVZD7c0jYw6rDxCcAQYcMsFj27thf7KkDhpj0EA0g9KHPxbFzHuDoc6US2EPS/MtplkNj8sbCx4Q==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-queueless-pushable": "^2.0.0" + } + }, + "node_modules/it-pair": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/it-pair/-/it-pair-2.0.6.tgz", + "integrity": "sha512-5M0t5RAcYEQYNG5BV7d7cqbdwbCAp5yLdzvkxsZmkuZsLbTdZzah6MQySYfaAQjNDCq6PUnDt0hqBZ4NwMfW6g==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-stream-types": "^2.0.1", + "p-defer": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-parallel": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/it-parallel/-/it-parallel-3.0.13.tgz", + "integrity": "sha512-85PPJ/O8q97Vj9wmDTSBBXEkattwfQGruXitIzrh0RLPso6RHfiVqkuTqBNufYYtB1x6PSkh0cwvjmMIkFEPHA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "p-defer": "^4.0.1" + } + }, + "node_modules/it-peekable": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/it-peekable/-/it-peekable-3.0.8.tgz", + "integrity": "sha512-7IDBQKSp/dtBxXV3Fj0v3qM1jftJ9y9XrWLRIuU1X6RdKqWiN60syNwP0fiDxZD97b8SYM58dD3uklIk1TTQAw==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/it-pipe": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/it-pipe/-/it-pipe-3.0.1.tgz", + "integrity": "sha512-sIoNrQl1qSRg2seYSBH/3QxWhJFn9PKYvOf/bHdtCBF0bnghey44VyASsWzn5dAx0DCDDABq1hZIuzKmtBZmKA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-merge": "^3.0.0", + "it-pushable": "^3.1.2", + "it-stream-types": "^2.0.1" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-pushable": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/it-pushable/-/it-pushable-3.2.3.tgz", + "integrity": "sha512-gzYnXYK8Y5t5b/BnJUr7glfQLO4U5vyb05gPx/TyTw+4Bv1zM9gFk4YsOrnulWefMewlphCjKkakFvj1y99Tcg==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "p-defer": "^4.0.0" + } + }, + "node_modules/it-queue": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/it-queue/-/it-queue-1.1.0.tgz", + "integrity": "sha512-aK9unJRIaJc9qiv53LByhF7/I2AuD7Ro4oLfLieVLL9QXNvRx++ANMpv8yCp2UO0KAtBuf70GOxSYb6ElFVRpQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "abort-error": "^1.0.1", + "it-pushable": "^3.2.3", + "main-event": "^1.0.0", + "race-event": "^1.3.0", + "race-signal": "^1.1.3" + } + }, + "node_modules/it-queueless-pushable": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/it-queueless-pushable/-/it-queueless-pushable-2.0.2.tgz", + "integrity": "sha512-2BqIt7XvDdgEgudLAdJkdseAwbVSBc0yAd8yPVHrll4eBuJPWIj9+8C3OIxzEKwhswLtd3bi+yLrzgw9gCyxMA==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "abort-error": "^1.0.1", + "p-defer": "^4.0.1", + "race-signal": "^1.1.3" + } + }, + "node_modules/it-reader": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/it-reader/-/it-reader-6.0.4.tgz", + "integrity": "sha512-XCWifEcNFFjjBHtor4Sfaj8rcpt+FkY0L6WdhD578SCDhV4VUm7fCkF3dv5a+fTcfQqvN9BsxBTvWbYO6iCjTg==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-stream-types": "^2.0.1", + "uint8arraylist": "^2.0.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/it-sort": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/it-sort/-/it-sort-3.0.9.tgz", + "integrity": "sha512-jsM6alGaPiQbcAJdzMsuMh00uJcI+kD9TBoScB8TR75zUFOmHvhSsPi+Dmh2zfVkcoca+14EbfeIZZXTUGH63w==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "it-all": "^3.0.0" + } + }, + "node_modules/it-stream-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/it-stream-types/-/it-stream-types-2.0.2.tgz", + "integrity": "sha512-Rz/DEZ6Byn/r9+/SBCuJhpPATDF9D+dz5pbgSUyBsCDtza6wtNATrz/jz1gDyNanC3XdLboriHnOC925bZRBww==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/it-take": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/it-take/-/it-take-3.0.9.tgz", + "integrity": "sha512-XMeUbnjOcgrhFXPUqa7H0VIjYSV/BvyxxjCp76QHVAFDJw2LmR1SHxUFiqyGeobgzJr7P2ZwSRRJQGn4D2BVlA==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/java-properties": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/java-properties/-/java-properties-1.0.2.tgz", + "integrity": "sha512-qjdpeo2yKlYTH7nFdK0vbZWuTCesk4o63v5iVOlhMQPfuIZQfW/HI35SjfhA+4qpg36rnFSvUK5b1m+ckIblQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/jest-message-util/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/jest-util/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD" + }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.1.0.tgz", + "integrity": "sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/junk": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/junk/-/junk-4.0.1.tgz", + "integrity": "sha512-Qush0uP+G8ZScpGMZvHUiRfI0YBWuB3gVBYlI0v0vvOJt5FLicco+IkP0a50LqTTQhmts/m6tP5SWE+USyIvcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ky": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/ky/-/ky-1.8.2.tgz", + "integrity": "sha512-XybQJ3d4Ea1kI27DoelE5ZCT3bSJlibYTtQuMsyzKox3TMyayw1asgQdl54WroAm+fIA3ZCr8zXW2RpR7qWVpA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sindresorhus/ky?sponsor=1" + } + }, + "node_modules/latest-version": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-9.0.0.tgz", + "integrity": "sha512-7W0vV3rqv5tokqkBAFV1LbR7HPOWzXQDpDgEuib/aJ1jsZZx6x3c2mBI+TJhJzOhkGeaLbCKEHXEXLfirtG2JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-json": "^10.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libp2p": { + "resolved": "packages/libp2p", + "link": true + }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/listr": { + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/listr/-/listr-0.14.3.tgz", + "integrity": "sha512-RmAl7su35BFd/xoMamRjpIE4j3v+L28o8CT5YhAXQJm1fD+1l9ngXY8JAQRJ+tFK2i5njvi0iRUKV09vPwA0iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@samverschueren/stream-to-observable": "^0.3.0", + "is-observable": "^1.1.0", + "is-promise": "^2.1.0", + "is-stream": "^1.1.0", + "listr-silent-renderer": "^1.1.1", + "listr-update-renderer": "^0.5.0", + "listr-verbose-renderer": "^0.5.0", + "p-map": "^2.0.0", + "rxjs": "^6.3.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/listr-silent-renderer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/listr-silent-renderer/-/listr-silent-renderer-1.1.1.tgz", + "integrity": "sha512-L26cIFm7/oZeSNVhWB6faeorXhMg4HNlb/dS/7jHhr708jxlXrtrBWo4YUxZQkc6dGoxEAe6J/D3juTRBUzjtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/listr-update-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-update-renderer/-/listr-update-renderer-0.5.0.tgz", + "integrity": "sha512-tKRsZpKz8GSGqoI/+caPmfrypiaq+OQCbd+CovEC24uk1h952lVj5sC7SqyFUm+OaJ5HN/a1YLt5cit2FMNsFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^1.1.3", + "cli-truncate": "^0.2.1", + "elegant-spinner": "^1.0.1", + "figures": "^1.7.0", + "indent-string": "^3.0.0", + "log-symbols": "^1.0.2", + "log-update": "^2.3.0", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "listr": "^0.14.2" + } + }, + "node_modules/listr-update-renderer/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/listr-update-renderer/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/listr-update-renderer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/listr-update-renderer/node_modules/figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/listr-update-renderer/node_modules/indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha512-BYqTHXTGUIvg7t1r4sJNKcbDZkL92nkXA8YtRpbjFHRHGDL/NtUeiBJMeE60kIFN/Mg8ESaWQvftaYMGJzQZCQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/listr-update-renderer/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/listr-verbose-renderer": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/listr-verbose-renderer/-/listr-verbose-renderer-0.5.0.tgz", + "integrity": "sha512-04PDPqSlsqIOaaaGZ+41vq5FejI9auqTInicFRndCBgE3bXG8D6W1I+mWhk+1nqbHmyhla/6BUrd5OSiHwKRXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.4.1", + "cli-cursor": "^2.1.0", + "date-fns": "^1.27.2", + "figures": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/listr-verbose-renderer/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/listr-verbose-renderer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/listr-verbose-renderer/node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/listr-verbose-renderer/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/listr-verbose-renderer/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/listr/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/listr/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/load-json-file/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.capitalize": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz", + "integrity": "sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.escaperegexp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz", + "integrity": "sha512-TM9YBvyC84ZxE3rgfefxUWiQKLilstD6k7PTGt6wfbtXF8ixIJLOL3VYyV/z+ZiPLsVxAsKAFVwWlWeb2Y8Yyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT" + }, + "node_modules/lodash.uniqby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz", + "integrity": "sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/log-update": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", + "integrity": "sha512-vlP11XfFGyeNQlmEn9tJ66rEW1coA/79m5z6BCkudjbAGE83uhAcGYrBFwfs3AdLiLzGRusRPAbSPK9xZteCmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^3.0.0", + "cli-cursor": "^2.0.0", + "wrap-ansi": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "license": "MIT", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/main-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/main-event/-/main-event-1.0.1.tgz", + "integrity": "sha512-NWtdGrAca/69fm6DIVd8T9rtfDII4Q8NQbIbsKQq2VzS9eqOGYs8uaNQjcuaCq/d9H/o625aOTJX2Qoxzqw0Pw==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/markdown-it": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/markdown-it/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/markdown-table": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.4.tgz", + "integrity": "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "15.0.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", + "integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/marked-terminal": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/marked-terminal/-/marked-terminal-7.3.0.tgz", + "integrity": "sha512-t4rBvPsHc57uE/2nJOLmMbZCQ4tgAccAED3ngXQqW6g+TxA488JzJ+FK3lQkzBQOI1mRV/r/Kq+1ZlJ4D0owQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "ansi-regex": "^6.1.0", + "chalk": "^5.4.1", + "cli-highlight": "^2.1.11", + "cli-table3": "^0.6.5", + "node-emoji": "^2.2.0", + "supports-hyperlinks": "^3.1.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "marked": ">=1 <16" + } + }, + "node_modules/marked-terminal/node_modules/ansi-escapes": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.0.0.tgz", + "integrity": "sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "license": "Apache-2.0" + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/matchit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/matchit/-/matchit-1.1.0.tgz", + "integrity": "sha512-+nGYoOlfHmxe5BW5tE0EMJppXEwdSf8uBA1GTZC7Q77kbT35+VKLYJMzVNWCHSsga1ps1tPYFtFyvxvKzWVmMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@arr/every": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.2.tgz", + "integrity": "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.2.tgz", + "integrity": "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.1.0.tgz", + "integrity": "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.1.tgz", + "integrity": "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.2.tgz", + "integrity": "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT" + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/meow": { + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-options/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.82.5.tgz", + "integrity": "sha512-8oAXxL7do8QckID/WZEKaIFuQJFUTLzfVcC48ghkHhNK2RGuQq8Xvf4AVd+TUA0SZtX0q8TGNXZ/eba1ckeGCg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "@babel/types": "^7.25.2", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.29.1", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.82.5", + "metro-cache": "0.82.5", + "metro-cache-key": "0.82.5", + "metro-config": "0.82.5", + "metro-core": "0.82.5", + "metro-file-map": "0.82.5", + "metro-resolver": "0.82.5", + "metro-runtime": "0.82.5", + "metro-source-map": "0.82.5", + "metro-symbolicate": "0.82.5", + "metro-transform-plugins": "0.82.5", + "metro-transform-worker": "0.82.5", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.82.5.tgz", + "integrity": "sha512-W/scFDnwJXSccJYnOFdGiYr9srhbHPdxX9TvvACOFsIXdLilh3XuxQl/wXW6jEJfgIb0jTvoTlwwrqvuwymr6Q==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.29.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "node_modules/metro-cache": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.82.5.tgz", + "integrity": "sha512-AwHV9607xZpedu1NQcjUkua8v7HfOTKfftl6Vc9OGr/jbpiJX6Gpy8E/V9jo/U9UuVYX2PqSUcVNZmu+LTm71Q==", + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.82.5" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-cache-key": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.82.5.tgz", + "integrity": "sha512-qpVmPbDJuRLrT4kcGlUouyqLGssJnbTllVtvIgXfR7ZuzMKf0mGS+8WzcqzNK8+kCyakombQWR0uDd8qhWGJcA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-config": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.82.5.tgz", + "integrity": "sha512-/r83VqE55l0WsBf8IhNmc/3z71y2zIPe5kRSuqA5tY/SL/ULzlHUJEMd1szztd0G45JozLwjvrhAzhDPJ/Qo/g==", + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "cosmiconfig": "^5.0.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.82.5", + "metro-cache": "0.82.5", + "metro-core": "0.82.5", + "metro-runtime": "0.82.5" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-config/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "license": "MIT", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-config/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "license": "MIT", + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-config/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-config/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/metro-core": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.82.5.tgz", + "integrity": "sha512-OJL18VbSw2RgtBm1f2P3J5kb892LCVJqMvslXxuxjAPex8OH7Eb8RBfgEo7VZSjgb/LOf4jhC4UFk5l5tAOHHA==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.82.5" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-file-map": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.82.5.tgz", + "integrity": "sha512-vpMDxkGIB+MTN8Af5hvSAanc6zXQipsAUO+XUx3PCQieKUfLwdoa8qaZ1WAQYRpaU+CJ8vhBcxtzzo3d9IsCIQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.82.5.tgz", + "integrity": "sha512-v6Nx7A4We6PqPu/ta1oGTqJ4Usz0P7c+3XNeBxW9kp8zayS3lHUKR0sY0wsCHInxZlNAEICx791x+uXytFUuwg==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-react-native-babel-preset": { + "version": "0.64.0", + "resolved": "https://registry.npmjs.org/metro-react-native-babel-preset/-/metro-react-native-babel-preset-0.64.0.tgz", + "integrity": "sha512-HcZ0RWQRuJfpPiaHyFQJzcym+/dDIVUPwUAXWoub/C4GkGu+mPjp8vqK6g0FxokCnnI2TK0gZTza2IDfiNNscQ==", + "deprecated": "Use @react-native/babel-preset instead", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.0.0", + "@babel/plugin-proposal-class-properties": "^7.0.0", + "@babel/plugin-proposal-export-default-from": "^7.0.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-optional-chaining": "^7.0.0", + "@babel/plugin-syntax-dynamic-import": "^7.0.0", + "@babel/plugin-syntax-export-default-from": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.0.0", + "@babel/plugin-syntax-optional-chaining": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.0.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.0.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-commonjs": "^7.0.0", + "@babel/plugin-transform-object-assign": "^7.0.0", + "@babel/plugin-transform-parameters": "^7.0.0", + "@babel/plugin-transform-react-display-name": "^7.0.0", + "@babel/plugin-transform-react-jsx": "^7.0.0", + "@babel/plugin-transform-react-jsx-self": "^7.0.0", + "@babel/plugin-transform-react-jsx-source": "^7.0.0", + "@babel/plugin-transform-regenerator": "^7.0.0", + "@babel/plugin-transform-runtime": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.5.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "@babel/template": "^7.0.0", + "react-refresh": "^0.4.0" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/metro-resolver": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.82.5.tgz", + "integrity": "sha512-kFowLnWACt3bEsuVsaRNgwplT8U7kETnaFHaZePlARz4Fg8tZtmRDUmjaD68CGAwc0rwdwNCkWizLYpnyVcs2g==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-runtime": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.82.5.tgz", + "integrity": "sha512-rQZDoCUf7k4Broyw3Ixxlq5ieIPiR1ULONdpcYpbJQ6yQ5GGEyYjtkztGD+OhHlw81LCR2SUAoPvtTus2WDK5g==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-source-map": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.82.5.tgz", + "integrity": "sha512-wH+awTOQJVkbhn2SKyaw+0cd+RVSCZ3sHVgyqJFQXIee/yLs3dZqKjjeKKhhVeudgjXo7aE/vSu/zVfcQEcUfw==", + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.82.5", + "nullthrows": "^1.1.1", + "ob1": "0.82.5", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.82.5.tgz", + "integrity": "sha512-1u+07gzrvYDJ/oNXuOG1EXSvXZka/0JSW1q2EYBWerVKMOhvv9JzDGyzmuV7hHbF2Hg3T3S2uiM36sLz1qKsiw==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.82.5", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-symbolicate/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-transform-plugins": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.82.5.tgz", + "integrity": "sha512-57Bqf3rgq9nPqLrT2d9kf/2WVieTFqsQ6qWHpEng5naIUtc/Iiw9+0bfLLWSAw0GH40iJ4yMjFcFJDtNSYynMA==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro-transform-worker": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.82.5.tgz", + "integrity": "sha512-mx0grhAX7xe+XUQH6qoHHlWedI8fhSpDGsfga7CpkO9Lk9W+aPitNtJWNGrW8PfjKEWbT9Uz9O50dkI8bJqigw==", + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "metro": "0.82.5", + "metro-babel-transformer": "0.82.5", + "metro-cache": "0.82.5", + "metro-cache-key": "0.82.5", + "metro-minify-terser": "0.82.5", + "metro-source-map": "0.82.5", + "metro-transform-plugins": "0.82.5", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/metro/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/metro/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/metro/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/metro/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.29.1.tgz", + "integrity": "sha512-jl+x31n4/w+wEqm0I2r4CMimukLbLQEYpisys5oCre611CI5fc9TxhqkBBCJ1edDG4Kza0f7CgNz8xVMLZQOmQ==", + "license": "MIT" + }, + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.29.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.29.1.tgz", + "integrity": "sha512-xBHWmUtRC5e/UL0tI7Ivt2riA/YBq9+SiYFU7C1oBa/j2jYGlIF9043oak1F47ihuDIxQ5nbsKueYJDRY02UgA==", + "license": "MIT", + "dependencies": { + "hermes-estree": "0.29.1" + } + }, + "node_modules/metro/node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/micromark": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz", + "integrity": "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz", + "integrity": "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.1.0.tgz", + "integrity": "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.1.0.tgz", + "integrity": "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.1.0.tgz", + "integrity": "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.1.1.tgz", + "integrity": "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.1.0.tgz", + "integrity": "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz", + "integrity": "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz", + "integrity": "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz", + "integrity": "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz", + "integrity": "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz", + "integrity": "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz", + "integrity": "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz", + "integrity": "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz", + "integrity": "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz", + "integrity": "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz", + "integrity": "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz", + "integrity": "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz", + "integrity": "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz", + "integrity": "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz", + "integrity": "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromark-util-types": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", + "dev": true, + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "license": "MIT" + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.7.tgz", + "integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa" + ], + "license": "MIT", + "bin": { + "mime": "bin/cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minimist-options/node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mocha": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.7.1.tgz", + "integrity": "sha512-5EK+Cty6KheMS/YLPPMJC64g5V61gIR25KsRItHw6x4hEKT6Njp1n9LOlH4gpevuwMVS66SXaBBpg+RWZkza4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "browser-stdout": "^1.3.1", + "chokidar": "^4.0.1", + "debug": "^4.3.5", + "diff": "^7.0.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^10.4.5", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^9.0.5", + "ms": "^2.1.3", + "picocolors": "^1.1.1", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^9.2.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1", + "yargs-unparser": "^2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/mocha/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/mocha/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/mocha/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/mocha/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mocha/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/mocha/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mocha/node_modules/diff": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-7.0.0.tgz", + "integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/mocha/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/mortice": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/mortice/-/mortice-3.3.1.tgz", + "integrity": "sha512-t3oESfijIPGsmsdLEKjF+grHfrbnKSXflJtgb1wY14cjxZpS6GnhHRXTxxzCAoCCnq1YYfpEPwY3gjiCPhOufQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "abort-error": "^1.0.0", + "it-queue": "^1.1.0", + "main-event": "^1.0.0" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/multiformats": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.4.0.tgz", + "integrity": "sha512-Mkb/QcclrJxKC+vrcIFl297h52QcKh2Az/9A5vbWytbQt4225UWWWmIuSsKksdww9NkIeYcA7DkfftyLuC/JSg==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/multimatch": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-5.0.0.tgz", + "integrity": "sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/multimatch/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/multimatch/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.5.tgz", + "integrity": "sha512-Ir/+ZpE9fDsNH0hQ3C68uyThDXzYcim2EqcZ8zn8Chtt1iylPT9xXJB0kPCnqzgcEGikO9RxSrh63MsmVCU7Fw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.js" + }, + "engines": { + "node": "^18 || >=20" + } + }, + "node_modules/napi-postinstall": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.2.tgz", + "integrity": "sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw==", + "dev": true, + "license": "MIT", + "bin": { + "napi-postinstall": "lib/cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/napi-postinstall" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true, + "license": "MIT" + }, + "node_modules/neostandard": { + "version": "0.12.2", + "resolved": "https://registry.npmjs.org/neostandard/-/neostandard-0.12.2.tgz", + "integrity": "sha512-VZU8EZpSaNadp3rKEwBhVD1Kw8jE3AftQLkCyOaM7bWemL1LwsYRsBnAmXy2LjG9zO8t66qJdqB7ccwwORyrAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", + "@stylistic/eslint-plugin": "2.11.0", + "eslint-import-resolver-typescript": "^3.10.1", + "eslint-plugin-import-x": "^4.16.1", + "eslint-plugin-n": "^17.20.0", + "eslint-plugin-promise": "^7.2.1", + "eslint-plugin-react": "^7.37.5", + "find-up": "^5.0.0", + "globals": "^15.15.0", + "peowly": "^1.3.2", + "typescript-eslint": "^8.35.1" + }, + "bin": { + "neostandard": "cli.mjs" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.0.0" + } + }, + "node_modules/neostandard/node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nerf-dart": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/nerf-dart/-/nerf-dart-1.0.0.tgz", + "integrity": "sha512-EZSPZB70jiVsivaBLYDCyntd5eH8NTSMOn3rB+HxwdmKThGELLdYv8qVIMWvZEFy9w8ZZpW9h9OB32l1rGtj7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-emoji": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.2.0.tgz", + "integrity": "sha512-Z3lTE9pLaJF47NyMhd4ww1yFTAP8YhYI8SleJiHzM46Fgpm5cnNzSl9XfzFNqbaz+VlJrIj3fXQ4DeN1Rjm6cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.6.0", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-emoji/node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT" + }, + "node_modules/node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "process-on-spawn": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.2.tgz", + "integrity": "sha512-Ee/R3SyN4BuynXcnTaekmaVdbDAEiNrHqjQIA37mHU8G9pf7aaAD4ZX3XjBLo6rsdcxA/gtkcNYZLt30ACgynw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm": { + "version": "10.9.3", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.9.3.tgz", + "integrity": "sha512-6Eh1u5Q+kIVXeA8e7l2c/HpnFFcwrkt37xDMujD5be1gloWa9p6j3Fsv3mByXXmqJHy+2cElRMML8opNT7xIJQ==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/redact", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], + "dev": true, + "license": "Artistic-2.0", + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^8.0.1", + "@npmcli/config": "^9.0.0", + "@npmcli/fs": "^4.0.0", + "@npmcli/map-workspaces": "^4.0.2", + "@npmcli/package-json": "^6.2.0", + "@npmcli/promise-spawn": "^8.0.2", + "@npmcli/redact": "^3.2.2", + "@npmcli/run-script": "^9.1.0", + "@sigstore/tuf": "^3.1.1", + "abbrev": "^3.0.1", + "archy": "~1.0.0", + "cacache": "^19.0.1", + "chalk": "^5.4.1", + "ci-info": "^4.2.0", + "cli-columns": "^4.0.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.4.5", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^8.1.0", + "ini": "^5.0.0", + "init-package-json": "^7.0.2", + "is-cidr": "^5.1.1", + "json-parse-even-better-errors": "^4.0.0", + "libnpmaccess": "^9.0.0", + "libnpmdiff": "^7.0.1", + "libnpmexec": "^9.0.1", + "libnpmfund": "^6.0.1", + "libnpmhook": "^11.0.0", + "libnpmorg": "^7.0.0", + "libnpmpack": "^8.0.1", + "libnpmpublish": "^10.0.1", + "libnpmsearch": "^8.0.0", + "libnpmteam": "^7.0.0", + "libnpmversion": "^7.0.0", + "make-fetch-happen": "^14.0.3", + "minimatch": "^9.0.5", + "minipass": "^7.1.1", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^11.2.0", + "nopt": "^8.1.0", + "normalize-package-data": "^7.0.0", + "npm-audit-report": "^6.0.0", + "npm-install-checks": "^7.1.1", + "npm-package-arg": "^12.0.2", + "npm-pick-manifest": "^10.0.0", + "npm-profile": "^11.0.1", + "npm-registry-fetch": "^18.0.2", + "npm-user-validate": "^3.0.0", + "p-map": "^7.0.3", + "pacote": "^19.0.1", + "parse-conflict-json": "^4.0.0", + "proc-log": "^5.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^4.1.0", + "semver": "^7.7.2", + "spdx-expression-parse": "^4.0.0", + "ssri": "^12.0.0", + "supports-color": "^9.4.0", + "tar": "^6.2.1", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^6.0.1", + "which": "^5.0.0", + "write-file-atomic": "^6.0.0" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm-package-json-lint": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/npm-package-json-lint/-/npm-package-json-lint-8.0.0.tgz", + "integrity": "sha512-44xqAKoV0nXnBYYLGUhMItGZb5tW3cLoW3UZxcsaCOX/YAkECrzOQA5F48oAA51vVE5CqAnsJB2CFvtolzMA3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.6", + "ajv-errors": "^1.0.1", + "chalk": "^4.1.2", + "cosmiconfig": "^8.3.6", + "debug": "^4.3.4", + "globby": "^11.1.0", + "ignore": "^5.3.1", + "is-plain-obj": "^3.0.0", + "jsonc-parser": "^3.2.1", + "log-symbols": "^4.1.0", + "meow": "^9.0.0", + "plur": "^4.0.0", + "semver": "^7.6.2", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1", + "type-fest": "^4.20.0", + "validate-npm-package-name": "^5.0.1" + }, + "bin": { + "npmPkgJsonLint": "dist/cli.js" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=9.0.0" + } + }, + "node_modules/npm-package-json-lint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm-package-json-lint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/npm-package-json-lint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm-package-json-lint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm-package-json-lint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/npm-package-json-lint/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/npm-package-json-lint/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-package-json-lint/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-json-lint/node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/npm-package-json-lint/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-package-json-lint/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-json-lint/node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/meow/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-package-json-lint/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-package-json-lint/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-package-json-lint/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-package-json-lint/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/npm-package-json-lint/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/npm-package-json-lint/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-package-json-lint/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-package-json-lint/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-package-json-lint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-package-json-lint/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/npm-package-json-lint/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-all/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/npm-run-all/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/npm-run-all/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/npm-run-all/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/npm-run-all/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/npm-run-all/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/npm-run-all/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^4.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/map-workspaces": "^4.0.1", + "@npmcli/metavuln-calculator": "^8.0.0", + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^6.0.1", + "@npmcli/query": "^4.0.0", + "@npmcli/redact": "^3.0.0", + "@npmcli/run-script": "^9.0.1", + "bin-links": "^5.0.0", + "cacache": "^19.0.1", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^10.2.2", + "minimatch": "^9.0.4", + "nopt": "^8.0.0", + "npm-install-checks": "^7.1.0", + "npm-package-arg": "^12.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.1", + "pacote": "^19.0.0", + "parse-conflict-json": "^4.0.0", + "proc-log": "^5.0.0", + "proggy": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "read-package-json-fast": "^4.0.0", + "semver": "^7.3.7", + "ssri": "^12.0.0", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^4.0.1", + "@npmcli/package-json": "^6.0.1", + "ci-info": "^4.0.0", + "ini": "^5.0.0", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "6.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^8.0.0", + "ini": "^5.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^10.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^19.0.0", + "json-parse-even-better-errors": "^4.0.0", + "pacote": "^20.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator/node_modules/pacote": { + "version": "20.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^9.0.0", + "cacache": "^19.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^12.0.0", + "npm-packlist": "^9.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^3.0.0", + "ssri": "^12.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "6.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^8.0.0", + "json-parse-even-better-errors": "^4.0.0", + "proc-log": "^5.0.0", + "semver": "^7.5.3", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "3.2.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "9.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^4.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "node-gyp": "^11.0.0", + "proc-log": "^5.0.0", + "which": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.4.3", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.4.1", + "tuf-js": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bin-links": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^7.0.0", + "npm-normalize-package-bin": "^4.0.0", + "proc-log": "^5.0.0", + "read-cmd-shim": "^5.0.0", + "write-file-atomic": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "19.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/chownr": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/mkdirp": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/tar": { + "version": "7.4.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/cacache/node_modules/yallist": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.4.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.2.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "4.1.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^5.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.4.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/diff": { + "version": "5.2.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.2", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/foreground-child": { + "version": "3.3.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "10.4.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^6.0.0", + "npm-package-arg": "^12.0.0", + "promzard": "^2.0.0", + "read": "^4.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/ip-address": { + "version": "9.0.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "5.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^4.1.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/jackspeak": { + "version": "3.4.3", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/npm/node_modules/jsbn": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^12.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.1", + "@npmcli/installed-package-contents": "^3.0.0", + "binary-extensions": "^2.3.0", + "diff": "^5.1.0", + "minimatch": "^9.0.4", + "npm-package-arg": "^12.0.0", + "pacote": "^19.0.0", + "tar": "^6.2.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "9.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.1", + "@npmcli/run-script": "^9.0.1", + "ci-info": "^4.0.0", + "npm-package-arg": "^12.0.0", + "pacote": "^19.0.0", + "proc-log": "^5.0.0", + "read": "^4.0.0", + "read-package-json-fast": "^4.0.0", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "11.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^8.0.1", + "@npmcli/run-script": "^9.0.1", + "npm-package-arg": "^12.0.0", + "pacote": "^19.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^7.0.0", + "npm-package-arg": "^12.0.0", + "npm-registry-fetch": "^18.0.1", + "proc-log": "^5.0.0", + "semver": "^7.3.7", + "sigstore": "^3.0.0", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^18.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.1", + "@npmcli/run-script": "^9.0.1", + "json-parse-even-better-errors": "^4.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "10.4.3", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "14.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "ssri": "^12.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/make-fetch-happen/node_modules/negotiator": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "9.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.1.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "11.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/chownr": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/mkdirp": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/tar": { + "version": "7.4.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/node-gyp/node_modules/yallist": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^3.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^8.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "7.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "12.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^6.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^7.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "10.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^7.1.0", + "npm-normalize-package-bin": "^4.0.0", + "npm-package-arg": "^12.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "11.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "18.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^3.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^14.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^12.0.0", + "proc-log": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "7.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/package-json-from-dist": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/npm/node_modules/pacote": { + "version": "19.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^6.0.0", + "@npmcli/installed-package-contents": "^3.0.0", + "@npmcli/package-json": "^6.0.0", + "@npmcli/promise-spawn": "^8.0.0", + "@npmcli/run-script": "^9.0.0", + "cacache": "^19.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^12.0.0", + "npm-packlist": "^9.0.0", + "npm-pick-manifest": "^10.0.0", + "npm-registry-fetch": "^18.0.0", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1", + "sigstore": "^3.0.0", + "ssri": "^12.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^4.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/proggy": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^2.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^4.0.0", + "npm-normalize-package-bin": "^4.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.7.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.0", + "@sigstore/sign": "^3.1.0", + "@sigstore/tuf": "^3.1.0", + "@sigstore/verify": "^2.1.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/bundle": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.4.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/core": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/sign": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.0", + "make-fetch-happen": "^14.0.2", + "proc-log": "^5.0.0", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/verify": { + "version": "2.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^3.1.0", + "@sigstore/core": "^2.0.0", + "@sigstore/protobuf-specs": "^0.4.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.8.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.5.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.21", + "dev": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/sprintf-js": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npm/node_modules/ssri": { + "version": "12.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "9.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tinyglobby": { + "version": "0.2.14", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "dev": true, + "inBundle": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "3.0.1", + "debug": "^4.3.6", + "make-fetch-happen": "^14.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/tuf-js/node_modules/@tufjs/models": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.5" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^5.0.0" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/which": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT" + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nyc": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-17.1.0.tgz", + "integrity": "sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^3.3.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^6.0.2", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/nyc/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/nyc/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/nyc/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/nyc/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/nyc/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nyc/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nyc/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nyc/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ob1": { + "version": "0.82.5", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.82.5.tgz", + "integrity": "sha512-QyQQ6e66f+Ut/qUVjEce0E/wux5nAGLXYZDn1jr15JWstHsCH3l6VVrg8NKDptW9NEiBXKOJeGF/ydxeSDF3IQ==", + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", + "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.values": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", + "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ora/node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/p-cancelable": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz", + "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/p-defer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-4.0.1.tgz", + "integrity": "sha512-Mr5KC5efvAK5VUptYEIopP1bakB85k2IWXaRC0rsh1uwn1L6M0LVml8OIQ4Gudg4oyZakf7FmeRLkMMtZW1i5A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-each-series": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", + "integrity": "sha512-lastgtAdoH9YaLyDa5i5z64q+kzOcQHsQ5SsZJD3q0VEyI8mq872S3geuNbRUQLVAE9siMfgKrpj7MloKFHruw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-event": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-6.0.1.tgz", + "integrity": "sha512-Q6Bekk5wpzW5qIyUP4gdMEujObYstZl6DMMOSenwBvV0BlE5LkDwkjs5yHbZmdCEq2o4RJx4tE1vwxFVf2FG1w==", + "license": "MIT", + "dependencies": { + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-filter": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-filter/-/p-filter-4.1.0.tgz", + "integrity": "sha512-37/tPdZ3oJwHaS3gNJdenCDB3Tz26i9sjhnguBtvN0vYlRIiDNnvTWkuh+0hETV9rLPdJ3rlL3yVOYPIAnM8rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-map": "^7.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-is-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-3.0.0.tgz", + "integrity": "sha512-Wo8VsW4IRQSKVXsJCn7TomUaVtyfjVDn3nUP7kE967BQk0CwFpdbZs0X0uk5sW9mkBa9eNM7hCMaG93WUAwxYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.3.tgz", + "integrity": "sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-queue": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.0.tgz", + "integrity": "sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-6.2.1.tgz", + "integrity": "sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==", + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.2", + "is-network-error": "^1.0.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-tap": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-tap/-/p-tap-3.1.0.tgz", + "integrity": "sha512-xJSaeByOOQu5GnHEcnrxMkNi8O3Ez5X1wz8RT6wiL3mJFd4oXcSOvcKq+1CFUtuVYTSTWL/8rlkaCJRoR+L+NA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-10.0.1.tgz", + "integrity": "sha512-ua1L4OgXSBdsu1FPb7F3tYH0F48a6kxvod4pLUlGY9COeJAJQNX/sNH2IiEmsxw7lqYiAwrdHMjz1FctOsyDQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ky": "^1.2.0", + "registry-auth-token": "^5.0.2", + "registry-url": "^6.0.1", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parent-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parse-imports-exports": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/parse-imports-exports/-/parse-imports-exports-0.2.4.tgz", + "integrity": "sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-statements": "1.0.11" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-statements": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/parse-statements/-/parse-statements-1.0.11.tgz", + "integrity": "sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true, + "license": "MIT" + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascalcase": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-2.0.0.tgz", + "integrity": "sha512-DHpENy5Qm/FaX+x3iBLoMLG/XHNCTgL+yErm1TwuVaj6u4fiOSkYkf60vGtITk7hrKHOO4uCl9vRrD4hqjNKjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.2.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/patch-package": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-6.5.1.tgz", + "integrity": "sha512-I/4Zsalfhc6bphmJTlrLoOcAF87jcxko4q0qsv4bGcurbr8IskEOtdnt9iCmsQVGL1B+iUhSQqweyTLJfCF9rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "cross-spawn": "^6.0.5", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "is-ci": "^2.0.0", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^5.6.0", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^1.10.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=10", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/patch-package/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/patch-package/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/patch-package/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/patch-package/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/patch-package/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/patch-package/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/patch-package/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/patch-package/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/patch-package/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/patch-package/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/patch-package/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/patch-package/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/patch-package/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/patch-package/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/patch-package/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/peowly": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/peowly/-/peowly-1.3.2.tgz", + "integrity": "sha512-BYIrwr8JCXY49jUZscgw311w9oGEKo7ux/s+BxrhKTQbiQ0iYNdZNJ5LgagaeercQdFHwnR7Z5IxxFWVQ+BasQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.6.0" + } + }, + "node_modules/pico-signals": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pico-signals/-/pico-signals-1.0.0.tgz", + "integrity": "sha512-Av5eg3cMtXbQVxVoIpP+dzHMBisRZuZy3htFWyaGGScT94AdfeT0On/QVhFNQhIMiY7aLi21W4pD+5KdWbEBUw==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", + "dev": true, + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha512-C+VUP+8jis7EsQZIhDYmS5qlNtjv2yP4SNtjXK9AP1ZcTRlnSfuumaTnRfYZnYgUUYVIKqL0fRvmUGDV2fmp6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-conf/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/playwright-core": { + "version": "1.54.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.54.1.tgz", + "integrity": "sha512-Nbjs2zjj0htNhzgiy5wu+3w09YetDx5pkrpI/kZotDlDUaYk0HVA5xrBVPdow4SAUIlhgKcJeJg4GRKW6xHusA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright-test": { + "version": "14.1.11", + "resolved": "https://registry.npmjs.org/playwright-test/-/playwright-test-14.1.11.tgz", + "integrity": "sha512-oAPpRTpjYWNUUshtaSdKGO6+tpH2eLDiVAjQoD5OGLgvefUnNA0L+tXXQrzwCFm5PyTMwAlmEBbUtMzJPFPThw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn-loose": "^8.3.0", + "assert": "^2.1.0", + "buffer": "^6.0.3", + "c8": "^10.1.3", + "camelcase": "^8.0.0", + "chokidar": "^4.0.3", + "cpy": "^11.0.0", + "esbuild": "0.25.8", + "esbuild-plugin-wasm": "^1.1.0", + "events": "^3.3.0", + "execa": "^9.3.0", + "exit-hook": "^4.0.0", + "globby": "^14.0.2", + "kleur": "^4.1.5", + "lilconfig": "^3.1.3", + "lodash": "^4.17.21", + "merge-options": "^3.0.4", + "nanoid": "^5.0.9", + "ora": "^8.0.1", + "p-timeout": "^6.1.4", + "path-browserify": "^1.0.1", + "playwright-core": "1.54.1", + "polka": "^0.5.2", + "premove": "^4.0.0", + "process": "^0.11.10", + "sade": "^1.8.1", + "sirv": "^3.0.0", + "source-map": "0.6.1", + "source-map-support": "^0.5.21", + "stream-browserify": "^3.0.0", + "tempy": "^3.1.0", + "test-exclude": "^7.0.1", + "util": "^0.12.5", + "v8-to-istanbul": "^9.3.0" + }, + "bin": { + "playwright-test": "cli.js", + "pw-test": "cli.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/playwright-test/node_modules/camelcase": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-8.0.0.tgz", + "integrity": "sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/playwright-test/node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/please-upgrade-node": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", + "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver-compare": "^1.0.0" + } + }, + "node_modules/plur": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-4.0.0.tgz", + "integrity": "sha512-4UGewrYgqDFw9vV6zNV+ADmPAUAfJPKtGvb/VdpQAx25X5f3xXdGdyOEVFwkl8Hl/tl7+xbeHqSEM+D5/TirUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "irregular-plurals": "^3.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/polka": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/polka/-/polka-0.5.2.tgz", + "integrity": "sha512-FVg3vDmCqP80tOrs+OeNlgXYmFppTXdjD5E7I4ET1NjvtNmQrb1/mJibybKkb/d4NA7YWAr1ojxuhpL3FHqdlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^0.5.0", + "trouter": "^2.0.1" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/premove": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/premove/-/premove-4.0.0.tgz", + "integrity": "sha512-zim/Hr4+FVdCIM7zL9b9Z0Wfd5Ya3mnKtiuDv7L5lzYzanSq6cOcVJ7EFcgK4I0pt28l8H0jX/x3nyog380XgQ==", + "dev": true, + "license": "MIT", + "bin": { + "premove": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "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==", + "license": "MIT" + }, + "node_modules/pretty-ms": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.2.0.tgz", + "integrity": "sha512-4yf0QO/sllf/1zbZWYnvWw3NxCQwLXKzIj0G849LSufP15BXKM0rbD2Z3wVnkMfjdn/CB0Dpp444gYAACdsplg==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/process-on-spawn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.1.0.tgz", + "integrity": "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fromentries": "^1.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/progress-events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.1.tgz", + "integrity": "sha512-MOzLIwhpt64KIVN64h1MwdKWiyKFNc/S6BoYKPIVUHFg0/eIEyBulhWCgn678v/4c0ri3FdGuzXymNCv02MUIw==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, + "node_modules/prompt": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/prompt/-/prompt-1.3.0.tgz", + "integrity": "sha512-ZkaRWtaLBZl7KKAKndKYUL8WqNT+cQHKRZnT4RYYms48jQkFw3rrBL+/N5K/KtdEveHkxs982MX2BkDKub2ZMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@colors/colors": "1.5.0", + "async": "3.2.3", + "read": "1.0.x", + "revalidator": "0.1.x", + "winston": "2.x" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/prompt/node_modules/async": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/proper-lockfile/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true, + "license": "ISC" + }, + "node_modules/protons-runtime": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-5.6.0.tgz", + "integrity": "sha512-/Kde+sB9DsMFrddJT/UZWe6XqvL7SL5dbag/DBCElFKhkwDj7XKt53S+mzLyaDP5OqS0wXjV5SA572uWDaT0Hg==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8-varint": "^2.0.2", + "uint8arraylist": "^2.4.3", + "uint8arrays": "^5.0.1" + } + }, + "node_modules/pump": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "dependencies": { + "inherits": "~2.0.3" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/race-event": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/race-event/-/race-event-1.6.1.tgz", + "integrity": "sha512-vi7WH5g5KoTFpu2mme/HqZiWH14XSOtg5rfp6raBskBHl7wnmy3F/biAIyY5MsK+BHWhoPhxtZ1Y2R7OHHaWyQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "abort-error": "^1.0.1" + } + }, + "node_modules/race-signal": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/race-signal/-/race-signal-1.1.3.tgz", + "integrity": "sha512-Mt2NznMgepLfORijhQMncE26IhkmjEphig+/1fKC0OtaKwys/gpvpmswSjoN01SS+VO951mj0L4VIDXdXsjnfA==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/ramda": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.2.tgz", + "integrity": "sha512-SbiLPU40JuJniHexQSAgad32hfwd+DRUdwF2PlVuI5RZD0/vahUco7R8vD86J/tcEKKF9vZrUVwgtmGCqlCKyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC" + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-devtools-core": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", + "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "node_modules/react-devtools-core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-native": { + "version": "0.80.2", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.80.2.tgz", + "integrity": "sha512-6ySV4qTJo/To3lgpG/9Mcg/ZtvExqOVZuT7JVGcO5rS2Bjvl/yUAkQF0hTnbRb2Ch6T5MlKghrM4OeHX+KA9Pg==", + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.7.0", + "@react-native/assets-registry": "0.80.2", + "@react-native/codegen": "0.80.2", + "@react-native/community-cli-plugin": "0.80.2", + "@react-native/gradle-plugin": "0.80.2", + "@react-native/js-polyfills": "0.80.2", + "@react-native/normalize-colors": "0.80.2", + "@react-native/virtualized-lists": "0.80.2", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-jest": "^29.7.0", + "babel-plugin-syntax-hermes-parser": "0.28.1", + "base64-js": "^1.5.1", + "chalk": "^4.0.0", + "commander": "^12.0.0", + "flow-enums-runtime": "^0.0.6", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jest-environment-node": "^29.7.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.82.2", + "metro-source-map": "^0.82.2", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.1", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.26.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.3", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/react": "^19.1.0", + "react": "^19.1.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native-test-runner": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/react-native-test-runner/-/react-native-test-runner-5.0.0.tgz", + "integrity": "sha512-/ztZUqRqV98/lLbGN781egGXjkR8i7MhfAm7nGtKe1DoDuITkvQk/4fF/nXfDyZEtaae9NYuv2MocUR/qcN1bQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-proposal-async-generator-functions": "^7.12.12", + "babel-plugin-transform-inline-environment-variables": "^0.4.3", + "chai": "^4.2.0", + "execa": "^4.1.0", + "find-up": "^5.0.0", + "fs-extra": "^9.0.1", + "globby": "^11.0.1", + "is-ci": "^2.0.0", + "is-uuid": "^1.0.2", + "lilconfig": "^2.0.2", + "meow": "^8.0.0", + "merge-options": "^3.0.4", + "metro-react-native-babel-preset": "^0.64.0", + "ora": "^5.1.0", + "p-retry": "^4.2.0", + "p-tap": "^3.1.0", + "patch-package": "^6.2.2", + "pico-signals": "^1.0.0", + "read-pkg": "^5.2.0", + "semver": "^7.3.4", + "tempy": "^1.0.0", + "yn": "^4.0.0" + }, + "bin": { + "rn-test": "cli/index.js" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/react-native-test-runner/node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-native-test-runner/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-native-test-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/react-native-test-runner/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/react-native-test-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-native-test-runner/node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/react-native-test-runner/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-test-runner/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-test-runner/node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/react-native-test-runner/node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-test-runner/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-test-runner/node_modules/meow": { + "version": "8.1.2", + "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", + "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react-native-test-runner/node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native-test-runner/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/react-native-test-runner/node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/react-native-test-runner/node_modules/read-pkg/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/react-native-test-runner/node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/react-native-test-runner/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/react-native-test-runner/node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react-native-test-runner/node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native-test-runner/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/react-native-test-runner/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/react-native/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/react-native/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/react-native/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/react-native/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/react-native/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/react-native/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/react-native/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/react-native/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/react-native/node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-refresh": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz", + "integrity": "sha512-Hwln1VNuGl/6bVwnd0Xdn1e84gT/8T9aYNL+HAKDArLCS7LWjwr7StE30IEYbIkx0Vi3vs+coQxe+SQDbGbbpA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/read-package-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-package-up/-/read-package-up-11.0.0.tgz", + "integrity": "sha512-MbgfoNPANMdb4oRBNg5eqLbB2t2r+o5Ua1pNt8BqGp4I0FJZhuVSOj3PaBPni4azWuSzEdNn2evevzVmEk1ohQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-11.0.0.tgz", + "integrity": "sha512-LOVbvF1Q0SZdjClSefZ0Nz5z8u+tIE7mV5NibzmE9VYmDe9CaBbAVtz1veOSZbofrdsilxuDAYnFenukZVp8/Q==", + "deprecated": "Renamed to read-package-up", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up-simple": "^1.0.0", + "read-pkg": "^9.0.0", + "type-fest": "^4.6.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz", + "integrity": "sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.2.0.tgz", + "integrity": "sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.2.0", + "regjsgen": "^0.8.0", + "regjsparser": "^0.12.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.1.0.tgz", + "integrity": "sha512-GdekYuwLXLxMuFTwAPg5UKGLW/UXzQrZvH/Zj791BQif5T05T0RsaLfHc9q3ZOKi7n+BoprPD9mJ0O0k4xzUlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/regjsparser": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.12.0.tgz", + "integrity": "sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "jsesc": "~3.0.2" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha512-gUAyHVHPPC5wdqX/LG4LWtRYtgjxyX78oanFNTMMyFEfOqdC54s3eE82imuWKbOeqYht2CrNf64Qb8vgmmtZGA==", + "dev": true, + "license": "ISC", + "dependencies": { + "es6-error": "^4.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true, + "license": "ISC" + }, + "node_modules/require-package-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/require-package-name/-/require-package-name-2.0.1.tgz", + "integrity": "sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/revalidator": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/revalidator/-/revalidator-0.1.8.tgz", + "integrity": "sha512-xcBILK2pA9oh4SiinPEZfhP8HfrB/ha+a2fTMyl7Om2WjlDVrOQy99N2MXXlUHqGJz4qEu2duXxHJjDWuK/0xg==", + "dev": true, + "license": "Apache 2.0", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/rimraf": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", + "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^11.0.0", + "package-json-from-dist": "^1.0.0" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.3.tgz", + "integrity": "sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.0.3", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/jackspeak": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.1.tgz", + "integrity": "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/lru-cache": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", + "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", + "dev": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "10.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", + "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@isaacs/brace-expansion": "^5.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/roarr/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-push-apply/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" + }, + "node_modules/semantic-release": { + "version": "24.2.7", + "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.7.tgz", + "integrity": "sha512-g7RssbTAbir1k/S7uSwSVZFfFXwpomUB9Oas0+xi9KStSCmeDXcA7rNhiskjLqvUe/Evhx8fVCT16OSa34eM5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/commit-analyzer": "^13.0.0-beta.1", + "@semantic-release/error": "^4.0.0", + "@semantic-release/github": "^11.0.0", + "@semantic-release/npm": "^12.0.2", + "@semantic-release/release-notes-generator": "^14.0.0-beta.1", + "aggregate-error": "^5.0.0", + "cosmiconfig": "^9.0.0", + "debug": "^4.0.0", + "env-ci": "^11.0.0", + "execa": "^9.0.0", + "figures": "^6.0.0", + "find-versions": "^6.0.0", + "get-stream": "^6.0.0", + "git-log-parser": "^1.2.0", + "hook-std": "^3.0.0", + "hosted-git-info": "^8.0.0", + "import-from-esm": "^2.0.0", + "lodash-es": "^4.17.21", + "marked": "^15.0.0", + "marked-terminal": "^7.3.0", + "micromatch": "^4.0.2", + "p-each-series": "^3.0.0", + "p-reduce": "^3.0.0", + "read-package-up": "^11.0.0", + "resolve-from": "^5.0.0", + "semver": "^7.3.2", + "semver-diff": "^4.0.0", + "signale": "^1.2.1", + "yargs": "^17.5.1" + }, + "bin": { + "semantic-release": "bin/semantic-release.js" + }, + "engines": { + "node": ">=20.8.1" + } + }, + "node_modules/semantic-release-monorepo": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/semantic-release-monorepo/-/semantic-release-monorepo-8.0.2.tgz", + "integrity": "sha512-TQC6KKIA0ATjii1OT0ZmQqcVzBJoaetJaJBC8FmKkg1IbDR4wBsuX6gl6UHDdijRDl8YyXqahj2hkJNyV6m9Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "execa": "^5.1.1", + "file-url": "^3.0.0", + "fs-extra": "^10.0.1", + "get-stream": "^6.0.1", + "git-log-parser": "^1.2.0", + "p-each-series": "^2.1.0", + "p-limit": "^3.1.0", + "pkg-up": "^3.1.0", + "ramda": "^0.27.2", + "read-pkg": "^5.2.0", + "semantic-release-plugin-decorators": "^4.0.0", + "tempy": "1.0.1" + }, + "peerDependencies": { + "semantic-release": ">=22.0.7" + } + }, + "node_modules/semantic-release-monorepo/node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release-monorepo/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/semantic-release-monorepo/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/semantic-release-monorepo/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release-monorepo/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/semantic-release-monorepo/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/semantic-release-monorepo/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release-monorepo/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/semantic-release-monorepo/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/semantic-release-monorepo/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release-monorepo/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release-monorepo/node_modules/p-each-series": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release-monorepo/node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release-monorepo/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semantic-release-monorepo/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/semantic-release-monorepo/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/semantic-release-monorepo/node_modules/temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release-monorepo/node_modules/tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release-monorepo/node_modules/tempy/node_modules/type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release-monorepo/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release-monorepo/node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semantic-release-plugin-decorators": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semantic-release-plugin-decorators/-/semantic-release-plugin-decorators-4.0.0.tgz", + "integrity": "sha512-5eqaITbgGJu7AWCqY/ZwDh3TCS84Q9i470AImwP9vw3YcFRyR8sEb499Zbnqa076bv02yFUn88GtloQMXQsBrg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "semantic-release": ">20" + } + }, + "node_modules/semantic-release/node_modules/@semantic-release/error": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-4.0.0.tgz", + "integrity": "sha512-mgdxrHTLOjOddRVYIYDo0fR3/v61GNN1YGkfbrjuIKg/uMgCd+Qzo3UAXJ+woLQQpos4pl5Esuw5A7AoNlzjUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/semantic-release/node_modules/aggregate-error": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-5.0.0.tgz", + "integrity": "sha512-gOsf2YwSlleG6IjRYG2A7k0HmBMEo6qVNk9Bp/EaLgAJT5ngH6PXbqa4ItvnEwCm/velL5jAnQgsHsWnjhGmvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^5.2.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/semantic-release/node_modules/clean-stack": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-5.2.0.tgz", + "integrity": "sha512-TyUIUJgdFnCISzG5zu3291TAsE77ddchd0bepon1VVQrKLGKFED4iXFEDQ24mIPdPBbyE16PK3F8MYE1CmcBEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/semantic-release/node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/semantic-release/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/hosted-git-info": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.1.0.tgz", + "integrity": "sha512-Rw/B2DNQaPBICNXEm8balFz9a6WpZrkCGpcWFpy7nCj+NyhSdqXipmfvtmWt9xGfp0wZnBxB+iVpLmQMYt47Tw==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/semantic-release/node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semantic-release/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/semantic-release/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/semantic-release/node_modules/p-reduce": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz", + "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT" + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-regex": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", + "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-error/node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-static/node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true, + "license": "ISC" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/signale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", + "integrity": "sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^2.3.2", + "figures": "^2.0.0", + "pkg-conf": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/signale/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/signale/node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha512-Oa2M9atig69ZkfwiApY8F2Yy+tzMbazyvqv21R0NsSC8floSOC09BbT1ITWAdoMGQvJ/aZnR1KMwdx9tvHnTNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/signale/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/sirv/node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", + "integrity": "sha512-up04hB2hR92PgjpyU3y/eg91yIBILyjVY26NvvciY3EVVPjybkMszMpXQ9QAkcS3I5rtJBDLoTxxg+qvW8c7rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/smol-toml": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/smol-toml/-/smol-toml-1.4.1.tgz", + "integrity": "sha512-CxdwHXyYTONGHThDbq5XdwbFsuY4wlClRGejfE2NtwUtiHYsP1QtNsHb/hnj31jKYSchztJsaA8pSQoVzkfCFg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 18" + }, + "funding": { + "url": "https://github.com/sponsors/cyyynthia" + } + }, + "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==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spawn-error-forwarder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spawn-error-forwarder/-/spawn-error-forwarder-1.0.0.tgz", + "integrity": "sha512-gRjMgK5uFjbCvdibeGJuy3I5OYz6VLoVdsOJdA6wV0WlfQVLFueoqMxwwYD9RODdgb6oUIvlRlsyFSiQkMKu0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/spawn-wrap/node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/spawn-wrap/node_modules/foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/spawn-wrap/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/spawn-wrap/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/spawn-wrap/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/spawn-wrap/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/spawn-wrap/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/split2": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-1.0.0.tgz", + "integrity": "sha512-NKywug4u4pX/AZBB1FCPzZ6/7O+Xhz1qMVbzTvvKvikjO99oPN87SkK08mEY9P63/5lWjK+wgOOgApnTg5r6qg==", + "dev": true, + "license": "ISC", + "dependencies": { + "through2": "~2.0.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "license": "BSD-3-Clause" + }, + "node_modules/stable-hash": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", + "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", + "dev": true, + "license": "MIT" + }, + "node_modules/stable-hash-x": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", + "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT" + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "license": "MIT", + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha512-3PnJbYgS56AeWgtKF5jtJRT6uFJe56Z0Hc5Ngg/6sI6rIt8iiMBTa9cvdyFfpMQjaVHr8dusbNeFGIIonxOvKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.12", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", + "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.6", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "internal-slot": "^1.1.0", + "regexp.prototype.flags": "^1.5.3", + "set-function-name": "^2.0.2", + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.repeat": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", + "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-bom": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-5.0.0.tgz", + "integrity": "sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.2.tgz", + "integrity": "sha512-4X2FR3UwhNUE9G49aIsJW5hRRR3GXGTBTZRMfv568O60ojM8HcWjV/VxAxCDW3SUND33O6ZY66ZuRcdkj73q2g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + }, + "bin": { + "sl-log-transformer": "bin/sl-log-transformer.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/super-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.0.0.tgz", + "integrity": "sha512-CY8u7DtbvucKuquCmOFEKhr9Besln7n9uN8eFbwcoGYWXOMW07u2o8njWaiXt11ylS3qoGF55pILjRmPlbodyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-timeout": "^1.0.1", + "time-span": "^5.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", + "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/temp-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-3.0.0.tgz", + "integrity": "sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + } + }, + "node_modules/tempy": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-3.1.0.tgz", + "integrity": "sha512-7jDLIdD2Zp0bDe5r3D2qtkd1QOCacylBuL7oa4udvN6v2pqr4+LcCr67C8DR1zkpaZ8XosF5m1yQSabKAW6f2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-stream": "^3.0.0", + "temp-dir": "^3.0.0", + "type-fest": "^2.12.2", + "unique-string": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tempy/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terser": { + "version": "5.43.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.43.1.tgz", + "integrity": "sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==", + "license": "BSD-2-Clause", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.14.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/test-exclude": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-7.0.1.tgz", + "integrity": "sha512-pFYqmTw68LXVjeWJMST4+borgQP2AyMNbg1BpZh9LbyhUeNkeaPF9gzfPGUAnSMV3qPYdWUwDIjjCLiSDOl7vg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^10.4.1", + "minimatch": "^9.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT" + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/time-span": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/time-span/-/time-span-5.1.0.tgz", + "integrity": "sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "convert-hrtime": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/traverse": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.8.tgz", + "integrity": "sha512-aXJDbk6SnumuaZSANd21XAo15ucCDE38H4fkqiGsc3MhCK+wOlZvLP9cB/TvpHT0mOyWgC4Z8EwRlzqYSUzdsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/trouter": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/trouter/-/trouter-2.0.1.tgz", + "integrity": "sha512-kr8SKKw94OI+xTGOkfsvwZQ8mWoikZDd2n8XZHjJVZUARZT+4/VV6cacRS6CLsH9bNm+HFIPU1Zx4CnNnb4qlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "matchit": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "dev": true, + "funding": [ + { + "type": "ko-fi", + "url": "https://ko-fi.com/rebeccastevens" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" + } + ], + "license": "BSD-3-Clause", + "dependencies": { + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": ">=4.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/ts-node/node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tsconfig-paths/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true, + "license": "0BSD" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typedoc": { + "version": "0.28.9", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.9.tgz", + "integrity": "sha512-aw45vwtwOl3QkUAmWCnLV9QW1xY+FSX2zzlit4MAfE99wX+Jij4ycnpbAWgBXsRrxmfs9LaYktg/eX5Bpthd3g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@gerrit0/mini-shiki": "^3.9.0", + "lunr": "^2.3.9", + "markdown-it": "^14.1.0", + "minimatch": "^9.0.5", + "yaml": "^2.8.0" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18", + "pnpm": ">= 10" + }, + "peerDependencies": { + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x" + } + }, + "node_modules/typedoc-plugin-mdn-links": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-5.0.7.tgz", + "integrity": "sha512-F4hSmW4wGn562EuF8UQWmutQfWlvSoP+14QJ6UQcNViGrBCQ9NLqze5LuhYc0DLxuQnWIzUnCShpuy2Zo5LtfQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typedoc": "0.27.x || 0.28.x" + } + }, + "node_modules/typedoc-plugin-mermaid": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-mermaid/-/typedoc-plugin-mermaid-1.12.0.tgz", + "integrity": "sha512-CRjw29j0YbQEh4ygG7xeGjq8zKUikgd1BBBrW3ttzTeCPLrNKZopWFPd1/leSb9dUEJ3p9exOO84aP4CgjYp3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "html-escaper": "^3.0.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kamiazya" + }, + "peerDependencies": { + "typedoc": ">=0.23.0 || 0.24.x || 0.25.x || 0.26.x" + } + }, + "node_modules/typedoc-plugin-mermaid/node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/typedoc-plugin-missing-exports": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-4.0.0.tgz", + "integrity": "sha512-Z4ei+853xppDEhcqzyeyRs4+R0kUuKQWnMK1EtSTEd5LFkgkdW5Bdn8vfo/rsCGbYVJxOWU99fxgM1mROw5Fug==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typedoc": "^0.28.1" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-docs-verifier": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/typescript-docs-verifier/-/typescript-docs-verifier-2.5.3.tgz", + "integrity": "sha512-fATV69QQZzIQWDGfUzo2USUcUTK0hPqTm7XZuyHf4QOkZUshnkwDk8TEk2IxaIlHxKjbM+5RtyDgxCtKYycjXA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "chalk": "^4.1.2", + "fs-extra": "^10.0.0", + "ora": "^5.4.1", + "strip-ansi": "^7.0.1", + "ts-node": "^10.8.1", + "tsconfig": "^7.0.0", + "yargs": "^17.5.1" + }, + "bin": { + "typescript-docs-verifier": "dist/bin/compile-typescript-docs.js" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "typescript": ">3.8.3" + } + }, + "node_modules/typescript-docs-verifier/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/typescript-docs-verifier/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/typescript-docs-verifier/node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-docs-verifier/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/typescript-docs-verifier/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript-docs-verifier/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/typescript-docs-verifier/node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-docs-verifier/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript-docs-verifier/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript-docs-verifier/node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/typescript-docs-verifier/node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript-docs-verifier/node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript-docs-verifier/node_modules/ora/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-docs-verifier/node_modules/ora/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-docs-verifier/node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/typescript-docs-verifier/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/typescript-docs-verifier/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/typescript-eslint": { + "version": "8.39.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.39.0.tgz", + "integrity": "sha512-lH8FvtdtzcHJCkMOKnN73LIn6SLTpoojgJqDAxPm1jCR14eWSGPX8ul/gggBdPMk/d5+u9V854vTYQ8T5jF/1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.39.0", + "@typescript-eslint/parser": "8.39.0", + "@typescript-eslint/typescript-estree": "8.39.0", + "@typescript-eslint/utils": "8.39.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uint8-varint": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.4.tgz", + "integrity": "sha512-FwpTa7ZGA/f/EssWAb5/YV6pHgVF1fViKdW8cWaEarjB8t7NyofSWBdOTyFPaGuUG4gx3v1O3PQ8etsiOs3lcw==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arraylist": "^2.0.0", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/uint8arraylist": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.8.tgz", + "integrity": "sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arrays": "^5.0.1" + } + }, + "node_modules/uint8arrays": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "multiformats": "^13.0.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "license": "MIT" + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", + "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz", + "integrity": "sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/universal-user-agent": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.3.tgz", + "integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==", + "dev": true, + "license": "ISC" + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unrs-resolver": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz", + "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "napi-postinstall": "^0.3.0" + }, + "funding": { + "url": "https://opencollective.com/unrs-resolver" + }, + "optionalDependencies": { + "@unrs/resolver-binding-android-arm-eabi": "1.11.1", + "@unrs/resolver-binding-android-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-arm64": "1.11.1", + "@unrs/resolver-binding-darwin-x64": "1.11.1", + "@unrs/resolver-binding-freebsd-x64": "1.11.1", + "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1", + "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-arm64-musl": "1.11.1", + "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1", + "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-gnu": "1.11.1", + "@unrs/resolver-binding-linux-x64-musl": "1.11.1", + "@unrs/resolver-binding-wasm32-wasi": "1.11.1", + "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1", + "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1", + "@unrs/resolver-binding-win32-x64-msvc": "1.11.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-join": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-5.0.0.tgz", + "integrity": "sha512-n2huDr9h9yzd6exQVnH/jU5mr+Pfx08LRXXZhkLLetAMESRj+anQsTAh940iMrIetKAmry9coFuZQ2jY8/p3WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true, + "license": "ISC" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", + "dev": true, + "license": "ISC", + "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/v8-to-istanbul/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==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz", + "integrity": "sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "license": "MIT" + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/weald": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/weald/-/weald-1.0.4.tgz", + "integrity": "sha512-+kYTuHonJBwmFhP1Z4YQK/dGi3jAnJGCYhyODFpHK73rbxnp9lnZQj7a2m+WVgn8fXr5bJaxUpF6l8qZpPeNWQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "ms": "^3.0.0-canary.1", + "supports-color": "^9.4.0" + } + }, + "node_modules/weald/node_modules/ms": { + "version": "3.0.0-canary.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-3.0.0-canary.1.tgz", + "integrity": "sha512-kh8ARjh8rMN7Du2igDRO9QJnqCb2xYTJxyQYK7vJJS4TvLLmsbyhiKpSW+t+y26gyOyMd0riphX0GeWKU3ky5g==", + "license": "MIT", + "engines": { + "node": ">=12.13" + } + }, + "node_modules/weald/node_modules/supports-color": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-9.4.0.tgz", + "integrity": "sha512-VL+lNrEoIXww1coLPOmiEmK/0sGigko5COxI09KzHc2VJXJsQ37UaQ+8quuxjDeA7+KnLGTWRyOXSLLR2Wb4jw==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT" + }, + "node_modules/wherearewe": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wherearewe/-/wherearewe-2.0.1.tgz", + "integrity": "sha512-XUguZbDxCA2wBn2LoFtcEhXL6AXo+hVjGonwhSTTTU9SzbWG8Xu3onNIpzf9j/mYUcJQ0f+m37SzG77G851uFw==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "is-electron": "^2.2.0" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/winston": { + "version": "2.4.7", + "resolved": "https://registry.npmjs.org/winston/-/winston-2.4.7.tgz", + "integrity": "sha512-vLB4BqzCKDnnZH9PHGoS2ycawueX4HLqENXQitvFHczhgW2vFpSOn31LZtVr1KU8YTw7DS4tM+cqyovxo8taVg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^2.6.4", + "colors": "1.0.x", + "cycle": "1.0.x", + "eyes": "0.1.x", + "isstream": "0.1.x", + "stack-trace": "0.0.x" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/winston/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/workerpool": { + "version": "9.3.3", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.3.tgz", + "integrity": "sha512-slxCaKbYjEdFT/o2rH9xS1hf4uRDch1w7Uo+apxhZ+sf/1d9e0ZVkn42kPNGP2dgjIx6YFvSevj0zHvbWe2jdw==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-3.0.1.tgz", + "integrity": "sha512-iXR3tDXpbnTpzjKSylUJRkLuOrEC7hwEB221cgn6wtF8wpmz28puFXAEfPT5zrjM3wahygB//VuWEr1vTkDcNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "string-width": "^2.1.1", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz", + "integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "license": "ISC" + }, + "node_modules/yaml": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz", + "integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser/node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yargs-unparser/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-4.0.0.tgz", + "integrity": "sha512-huWiiCS4TxKc4SfgmTwW1K7JmXPPAmuXWYy4j9qjQo4+27Kni8mGhAAi1cloRWmBe2EqcLgt3IGqQoRL/MtPgg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz", + "integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "packages/connection-encrypter-noise": { + "name": "@chainsafe/libp2p-noise", + "version": "16.1.4", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@chainsafe/as-chacha20poly1305": "^0.1.0", + "@chainsafe/as-sha256": "^1.0.0", + "@libp2p/crypto": "^5.0.0", + "@libp2p/interface": "^2.9.0", + "@libp2p/peer-id": "^5.0.0", + "@libp2p/utils": "^6.7.1", + "@noble/ciphers": "^1.1.3", + "@noble/curves": "^1.1.0", + "@noble/hashes": "^1.3.1", + "it-length-prefixed": "^10.0.1", + "it-length-prefixed-stream": "^2.0.1", + "it-pair": "^2.0.6", + "it-pipe": "^3.0.1", + "it-stream-types": "^2.0.1", + "protons-runtime": "^5.5.0", + "uint8arraylist": "^2.4.3", + "uint8arrays": "^5.0.0", + "wherearewe": "^2.0.1" + } + }, + "packages/crypto": { + "name": "@libp2p/crypto", + "version": "5.1.7", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@noble/curves": "^1.9.1", + "@noble/hashes": "^1.8.0", + "multiformats": "^13.3.6", + "protons-runtime": "^5.5.0", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + } + }, + "packages/interface": { + "name": "@libp2p/interface", + "version": "2.10.5", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@multiformats/dns": "^1.0.6", + "@multiformats/multiaddr": "^12.4.4", + "it-pushable": "^3.2.3", + "main-event": "^1.0.1", + "multiformats": "^13.3.6", + "progress-events": "^1.0.1", + "uint8arraylist": "^2.4.8" + }, + "devDependencies": { + "aegir": "^47.0.14" + } + }, + "packages/interface-internal": { + "name": "@libp2p/interface-internal", + "version": "2.3.18", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/peer-collections": "^6.0.34", + "@multiformats/multiaddr": "^12.4.4", + "progress-events": "^1.0.1" + } + }, + "packages/libp2p": { + "version": "2.9.0", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.1.0", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "@libp2p/interface-internal": "^2.3.18", + "@libp2p/logger": "^5.1.21", + "@libp2p/multistream-select": "^6.0.28", + "@libp2p/peer-collections": "^6.0.34", + "@libp2p/peer-id": "^5.1.8", + "@libp2p/peer-store": "^11.2.6", + "@libp2p/utils": "^6.7.1", + "@multiformats/dns": "^1.0.6", + "@multiformats/multiaddr": "^12.4.4", + "@multiformats/multiaddr-matcher": "^2.0.0", + "@types/react-native": "^0.73.0", + "any-signal": "^4.1.1", + "datastore-core": "^10.0.2", + "interface-datastore": "^8.3.1", + "it-merge": "^3.0.11", + "it-parallel": "^3.0.11", + "main-event": "^1.0.1", + "multiformats": "^13.3.6", + "p-defer": "^4.0.1", + "p-retry": "^6.2.1", + "progress-events": "^1.0.1", + "race-event": "^1.6.0", + "race-signal": "^1.1.3", + "uint8arrays": "^5.1.0" + } + }, + "packages/logger": { + "name": "@libp2p/logger", + "version": "5.1.21", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@multiformats/multiaddr": "^12.4.4", + "interface-datastore": "^8.3.1", + "multiformats": "^13.3.6", + "weald": "^1.0.4" + } + }, + "packages/multistream-select": { + "name": "@libp2p/multistream-select", + "version": "6.0.28", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/utils": "^6.7.1", + "it-length-prefixed": "^10.0.1", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + } + }, + "packages/peer-collections": { + "name": "@libp2p/peer-collections", + "version": "6.0.34", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/peer-id": "^5.1.8", + "@libp2p/utils": "^6.7.1", + "multiformats": "^13.3.6" + } + }, + "packages/peer-record": { + "name": "@libp2p/peer-record", + "version": "8.0.34", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "@libp2p/peer-id": "^5.1.8", + "@multiformats/multiaddr": "^12.4.4", + "multiformats": "^13.3.6", + "protons-runtime": "^5.5.0", + "uint8-varint": "^2.0.4", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + } + }, + "packages/protocol-perf": { + "name": "@libp2p/perf", + "version": "4.0.46", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/interface-internal": "^2.3.18", + "@multiformats/multiaddr": "^12.4.4", + "it-pushable": "^3.2.3", + "race-event": "^1.6.1", + "uint8arraylist": "^2.4.8" + } + }, + "packages/stream-multiplexer-yamux": { + "name": "@chainsafe/libp2p-yamux", + "version": "7.0.4", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.0.0", + "@libp2p/utils": "^6.0.0", + "race-signal": "^1.1.3", + "uint8arraylist": "^2.4.8" + } + }, + "packages/transport-tcp": { + "name": "@libp2p/tcp", + "version": "10.1.18", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/utils": "^6.7.1", + "@multiformats/multiaddr": "^12.4.4", + "@multiformats/multiaddr-matcher": "^2.0.0", + "@types/sinon": "^17.0.4", + "main-event": "^1.0.1", + "p-event": "^6.0.1", + "progress-events": "^1.0.1", + "race-event": "^1.6.0" + } + }, + "packages/utils": { + "name": "@libp2p/utils", + "version": "6.7.1", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.1.0", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "@libp2p/logger": "^5.1.21", + "@multiformats/multiaddr": "^12.4.4", + "@sindresorhus/fnv1a": "^3.1.0", + "@types/netmask": "^2.0.5", + "any-signal": "^4.1.1", + "delay": "^6.0.0", + "is-loopback-addr": "^2.0.2", + "is-plain-obj": "^4.1.0", + "it-length-prefixed": "^10.0.1", + "it-pipe": "^3.0.1", + "it-pushable": "^3.2.3", + "it-stream-types": "^2.0.2", + "main-event": "^1.0.1", + "netmask": "^2.0.2", + "p-defer": "^4.0.1", + "p-event": "^6.0.1", + "race-event": "^1.6.0", + "race-signal": "^1.1.3", + "uint8-varint": "^2.0.4", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + } + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/package.json new file mode 100644 index 000000000..63f09d20e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/package.json @@ -0,0 +1,50 @@ +{ + "name": "js-libp2p-monorepo", + "version": "1.0.0", + "description": "JavaScript implementation of libp2p, a modular peer to peer network stack", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "private": true, + "scripts": { + "reset": "aegir run clean && aegir clean interop/node_modules packages/*/node_modules node_modules package-lock.json packages/*/package-lock.json interop/*/package-lock.json", + "test": "aegir run test", + "test:node": "aegir run test:node", + "test:chrome": "aegir run test:chrome", + "test:chrome-webworker": "aegir run test:chrome-webworker", + "test:firefox": "aegir run test:firefox", + "test:firefox-webworker": "aegir run test:firefox-webworker", + "test:electron-main": "aegir run test:electron-main", + "test:webkit": "aegir run test:webkit", + "test:cli": "aegir run test:cli", + "test:interop": "aegir run test:interop", + "coverage": "aegir run coverage", + "build": "aegir run build", + "generate": "aegir run generate", + "clean": "aegir run clean", + "lint": "aegir run lint", + "dep-check": "aegir run dep-check", + "doc-check": "aegir run doc-check", + "spell-check": "aegir spell-check", + "release": "run-s build docs:no-publish npm:release docs", + "npm:release": "aegir exec --bail false npm -- publish", + "release:rc": "aegir release-rc", + "docs": "aegir docs", + "docs:no-publish": "aegir docs --publish false -- --exclude interop --exclude doc" + }, + "devDependencies": { + "aegir": "^47.0.6", + "npm-run-all": "^4.1.5" + }, + "workspaces": [ + "doc", + "interop", + "packages/*" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/.aegir.js b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/.aegir.js new file mode 100644 index 000000000..95c3276d2 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/.aegir.js @@ -0,0 +1,7 @@ + +/** @type {import('aegir').PartialOptions} */ +export default { + docs: { + entryPoint: "src/index.ts" + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/README.md new file mode 100644 index 000000000..177b73b94 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/README.md @@ -0,0 +1,95 @@ +# @chainsafe/libp2p-noise + +![npm](https://img.shields.io/npm/v/@chainsafe/libp2p-noise) +[![](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-noise/js-test-and-release.yml?branch=master)](https://github.com/ChainSafe/js-libp2p-noise/actions) +[![](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](https://libp2p.io/) +![](https://img.shields.io/github/issues-raw/ChainSafe/js-libp2p-noise) +[![License Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) +[![License MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +![](https://img.shields.io/badge/npm-%3E%3D7.0.0-orange.svg?style=flat-square) +![](https://img.shields.io/badge/Node.js-%3E%3D16.0.0-orange.svg?style=flat-square) +![](https://img.shields.io/badge/browsers-last%202%20versions%2C%20not%20ie%20%3C%3D11-orange) +[![Twitter](https://img.shields.io/twitter/follow/ChainSafeth.svg?label=Twitter)](https://twitter.com/ChainSafeth) +[![Discord](https://img.shields.io/discord/593655374469660673.svg?label=Discord\&logo=discord)](https://discord.gg/Q6A3YA2) + +> Noise libp2p handshake for js-libp2p + +# About + + + +This repository contains TypeScript implementation of noise protocol, an encryption protocol used in libp2p. + +## Usage + +Install with `yarn add @chainsafe/libp2p-noise` or `npm i @chainsafe/libp2p-noise`. + +Example of using default noise configuration and passing it to the libp2p config: + +```ts +import {createLibp2p} from "libp2p" +import {noise} from "@chainsafe/libp2p-noise" + +//custom noise configuration, pass it instead of `noise()` +//x25519 private key +const n = noise({ staticNoiseKey }); + +const libp2p = await createLibp2p({ + connectionEncrypters: [noise()], + //... other options +}) +``` + +See the [NoiseInit](https://github.com/ChainSafe/js-libp2p-noise/blob/master/src/noise.ts#L22-L30) interface for noise configuration options. + +## API + +This module exposes an implementation of the [ConnectionEncrypter](https://libp2p.github.io/js-libp2p/interfaces/_libp2p_interface.ConnectionEncrypter.html) interface. + +## Bring your own crypto + +You can provide a custom crypto implementation (instead of the default, based on [@noble](https://paulmillr.com/noble/)) by adding a `crypto` field to the init argument passed to the `Noise` factory. + +The implementation must conform to the `ICryptoInterface`, defined in + +# Install + +```console +$ npm i @chainsafe/libp2p-noise +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/ChainSafe/js-libp2p-noise/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/ChainSafe/js-libp2p-noise/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/package.json new file mode 100644 index 000000000..9917039e2 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/package.json @@ -0,0 +1,171 @@ +{ + "name": "@chainsafe/libp2p-noise", + "version": "16.1.4", + "description": "Noise libp2p handshake for js-libp2p", + "author": "ChainSafe ", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/ChainSafe/js-libp2p-noise#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/ChainSafe/js-libp2p-noise.git" + }, + "bugs": { + "url": "https://github.com/ChainSafe/js-libp2p-noise/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "crypto", + "libp2p", + "noise" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "release": { + "branches": [ + "master" + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "releaseRules": [ + { + "breaking": true, + "release": "major" + }, + { + "revert": true, + "release": "patch" + }, + { + "type": "feat", + "release": "minor" + }, + { + "type": "fix", + "release": "patch" + }, + { + "type": "docs", + "release": "patch" + }, + { + "type": "test", + "release": "patch" + }, + { + "type": "deps", + "release": "patch" + }, + { + "scope": "no-release", + "release": false + } + ] + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "presetConfig": { + "types": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "chore", + "section": "Trivial Changes" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "deps", + "section": "Dependencies" + }, + { + "type": "test", + "section": "Tests" + } + ] + } + } + ], + "@semantic-release/changelog", + "@semantic-release/npm", + "@semantic-release/github", + [ + "@semantic-release/git", + { + "assets": [ + "CHANGELOG.md", + "package.json" + ] + } + ] + ] + }, + "scripts": { + "bench": "node benchmarks/benchmark.js", + "clean": "aegir clean", + "dep-check": "aegir dep-check", + "build": "aegir build", + "lint": "aegir lint", + "lint:fix": "aegir lint --fix", + "test": "aegir test", + "test:node": "aegir test -t node", + "test:browser": "aegir test -t browser -t webworker", + "test:electron-main": "aegir test -t electron-main", + "test:interop": "aegir test -t node -f dist/test/interop.js", + "docs": "aegir docs", + "proto:gen": "protons ./src/proto/payload.proto", + "prepublish": "npm run build", + "release": "aegir release" + }, + "dependencies": { + "@chainsafe/as-chacha20poly1305": "^0.1.0", + "@chainsafe/as-sha256": "^1.0.0", + "@libp2p/crypto": "^5.0.0", + "@libp2p/interface": "^2.9.0", + "@libp2p/peer-id": "^5.0.0", + "@libp2p/utils": "^6.7.1", + "@noble/ciphers": "^1.1.3", + "@noble/curves": "^1.1.0", + "@noble/hashes": "^1.3.1", + "it-length-prefixed": "^10.0.1", + "it-length-prefixed-stream": "^2.0.1", + "it-pair": "^2.0.6", + "it-pipe": "^3.0.1", + "it-stream-types": "^2.0.1", + "protons-runtime": "^5.5.0", + "uint8arraylist": "^2.4.3", + "uint8arrays": "^5.0.0", + "wherearewe": "^2.0.1" + }, + "browser": { + "./dist/src/crypto/index.js": "./dist/src/crypto/index.browser.js" + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/constants.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/constants.ts new file mode 100644 index 000000000..7c25217c0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/constants.ts @@ -0,0 +1,5 @@ +export const NOISE_MSG_MAX_LENGTH_BYTES = 65535 +export const NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG = NOISE_MSG_MAX_LENGTH_BYTES - 16 + +export const DUMP_SESSION_KEYS = Boolean(globalThis.process?.env?.DUMP_SESSION_KEYS) +export const CHACHA_TAG_LENGTH = 16 \ No newline at end of file diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto.ts new file mode 100644 index 000000000..75c0f5781 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto.ts @@ -0,0 +1,27 @@ +import type { ICrypto, KeyPair } from './types.js' +import type { Uint8ArrayList } from 'uint8arraylist' + +/** Underlying crypto implementation, meant to be overridable */ +export interface ICryptoInterface { + hashSHA256(data: Uint8Array | Uint8ArrayList): Uint8Array + + getHKDF(ck: Uint8Array, ikm: Uint8Array): [Uint8Array, Uint8Array, Uint8Array] + + generateX25519KeyPair(): KeyPair + generateX25519KeyPairFromSeed(seed: Uint8Array): KeyPair + generateX25519SharedKey(privateKey: Uint8Array | Uint8ArrayList, publicKey: Uint8Array | Uint8ArrayList): Uint8Array + + chaCha20Poly1305Encrypt(plaintext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array): Uint8ArrayList | Uint8Array + chaCha20Poly1305Decrypt(ciphertext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array, dst?: Uint8Array): Uint8ArrayList | Uint8Array +} + +export function wrapCrypto (crypto: ICryptoInterface): ICrypto { + return { + generateKeypair: crypto.generateX25519KeyPair, + dh: (keypair, publicKey) => crypto.generateX25519SharedKey(keypair.privateKey, publicKey).subarray(0, 32), + encrypt: crypto.chaCha20Poly1305Encrypt, + decrypt: crypto.chaCha20Poly1305Decrypt, + hash: crypto.hashSHA256, + hkdf: crypto.getHKDF + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/index.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/index.browser.ts new file mode 100644 index 000000000..39c9ea7d0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/index.browser.ts @@ -0,0 +1,3 @@ +import { pureJsCrypto } from './js.js' + +export const defaultCrypto = pureJsCrypto diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/index.ts new file mode 100644 index 000000000..6d3639bb9 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/index.ts @@ -0,0 +1,219 @@ +import crypto from 'node:crypto' +import { newInstance, ChaCha20Poly1305 } from '@chainsafe/as-chacha20poly1305' +import { digest } from '@chainsafe/as-sha256' +import { Uint8ArrayList } from 'uint8arraylist' +import { isElectronMain } from 'wherearewe' +import { pureJsCrypto } from './js.js' +import type { ICryptoInterface } from '../crypto.js' +import type { KeyPair } from '../types.js' + +const ctx = newInstance() +const asImpl = new ChaCha20Poly1305(ctx) +const CHACHA_POLY1305 = 'chacha20-poly1305' +const PKCS8_PREFIX = Buffer.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20]) +const X25519_PREFIX = Buffer.from([0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x03, 0x21, 0x00]) +const nodeCrypto: Pick = { + hashSHA256 (data) { + const hash = crypto.createHash('sha256') + + if (data instanceof Uint8Array) { + return hash.update(data).digest() + } + + for (const buf of data) { + hash.update(buf) + } + + return hash.digest() + }, + + chaCha20Poly1305Encrypt (plaintext, nonce, ad, k) { + const cipher = crypto.createCipheriv(CHACHA_POLY1305, k, nonce, { + authTagLength: 16 + }) + cipher.setAAD(ad, { plaintextLength: plaintext.byteLength }) + + if (plaintext instanceof Uint8Array) { + const updated = cipher.update(plaintext) + const final = cipher.final() + const tag = cipher.getAuthTag() + + return Buffer.concat([updated, final, tag], updated.byteLength + final.byteLength + tag.byteLength) + } + + const output = new Uint8ArrayList() + + for (const buf of plaintext) { + output.append(cipher.update(buf)) + } + + const final = cipher.final() + + if (final.byteLength > 0) { + output.append(final) + } + + output.append(cipher.getAuthTag()) + + return output + }, + + chaCha20Poly1305Decrypt (ciphertext, nonce, ad, k, _dst) { + const authTag = ciphertext.subarray(ciphertext.length - 16) + const decipher = crypto.createDecipheriv(CHACHA_POLY1305, k, nonce, { + authTagLength: 16 + }) + + let text: Uint8Array | Uint8ArrayList + + if (ciphertext instanceof Uint8Array) { + text = ciphertext.subarray(0, ciphertext.length - 16) + } else { + text = ciphertext.sublist(0, ciphertext.length - 16) + } + + decipher.setAAD(ad, { + plaintextLength: text.byteLength + }) + decipher.setAuthTag(authTag) + + if (text instanceof Uint8Array) { + const output = decipher.update(text) + const final = decipher.final() + + if (final.byteLength > 0) { + return Buffer.concat([output, final], output.byteLength + final.byteLength) + } + + return output + } + + const output = new Uint8ArrayList() + + for (const buf of text) { + output.append(decipher.update(buf)) + } + + const final = decipher.final() + + if (final.byteLength > 0) { + output.append(final) + } + + return output + } +} + +const asCrypto: Pick = { + hashSHA256 (data) { + return digest(data.subarray()) + }, + chaCha20Poly1305Encrypt (plaintext, nonce, ad, k) { + return asImpl.seal(k, nonce, plaintext.subarray(), ad) + }, + chaCha20Poly1305Decrypt (ciphertext, nonce, ad, k, dst) { + const plaintext = asImpl.open(k, nonce, ciphertext.subarray(), ad, dst) + if (!plaintext) { + throw new Error('Invalid chacha20poly1305 decryption') + } + return plaintext + } +} + +// benchmarks show that for chacha20poly1305 +// the as implementation is faster for smaller payloads(<1200) +// and the node implementation is faster for larger payloads +export const defaultCrypto: ICryptoInterface = { + ...pureJsCrypto, + hashSHA256 (data) { + return nodeCrypto.hashSHA256(data) + }, + chaCha20Poly1305Encrypt (plaintext, nonce, ad, k) { + if (plaintext.byteLength < 1200) { + return asCrypto.chaCha20Poly1305Encrypt(plaintext, nonce, ad, k) + } + return nodeCrypto.chaCha20Poly1305Encrypt(plaintext, nonce, ad, k) + }, + chaCha20Poly1305Decrypt (ciphertext, nonce, ad, k, dst) { + if (ciphertext.byteLength < 1200) { + return asCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst) + } + return nodeCrypto.chaCha20Poly1305Decrypt(ciphertext, nonce, ad, k, dst) + }, + generateX25519KeyPair (): KeyPair { + const { publicKey, privateKey } = crypto.generateKeyPairSync('x25519', { + publicKeyEncoding: { + type: 'spki', + format: 'der' + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'der' + } + }) + + return { + publicKey: publicKey.subarray(X25519_PREFIX.length), + privateKey: privateKey.subarray(PKCS8_PREFIX.length) + } + }, + generateX25519KeyPairFromSeed (seed: Uint8Array): KeyPair { + const privateKey = crypto.createPrivateKey({ + key: Buffer.concat([ + PKCS8_PREFIX, + seed + ], PKCS8_PREFIX.byteLength + seed.byteLength), + type: 'pkcs8', + format: 'der' + }) + + const publicKey = crypto.createPublicKey(privateKey) + .export({ + type: 'spki', + format: 'der' + }).subarray(X25519_PREFIX.length) + + return { + publicKey, + privateKey: seed + } + }, + generateX25519SharedKey (privateKey: Uint8Array | Uint8ArrayList, publicKey: Uint8Array | Uint8ArrayList): Uint8Array { + if (publicKey instanceof Uint8Array) { + publicKey = Buffer.concat([ + X25519_PREFIX, + publicKey + ], X25519_PREFIX.byteLength + publicKey.byteLength) + } else { + publicKey = new Uint8ArrayList(X25519_PREFIX, publicKey).subarray() + } + + if (privateKey instanceof Uint8Array) { + privateKey = Buffer.concat([ + PKCS8_PREFIX, + privateKey + ], PKCS8_PREFIX.byteLength + privateKey.byteLength) + } else { + privateKey = new Uint8ArrayList(PKCS8_PREFIX, privateKey).subarray() + } + + return crypto.diffieHellman({ + publicKey: crypto.createPublicKey({ + key: Buffer.from(publicKey.buffer, publicKey.byteOffset, publicKey.byteLength), + type: 'spki', + format: 'der' + }), + privateKey: crypto.createPrivateKey({ + key: Buffer.from(privateKey.buffer, privateKey.byteOffset, privateKey.byteLength), + type: 'pkcs8', + format: 'der' + }) + }) + } +} + +// no chacha20-poly1305 in electron https://github.com/electron/electron/issues/24024 +if (isElectronMain) { + defaultCrypto.chaCha20Poly1305Encrypt = asCrypto.chaCha20Poly1305Encrypt + defaultCrypto.chaCha20Poly1305Decrypt = asCrypto.chaCha20Poly1305Decrypt +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/js.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/js.ts new file mode 100644 index 000000000..7f9ca1684 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/crypto/js.ts @@ -0,0 +1,56 @@ +import { chacha20poly1305 } from '@noble/ciphers/chacha' +import { x25519 } from '@noble/curves/ed25519' +import { extract, expand } from '@noble/hashes/hkdf' +import { sha256 } from '@noble/hashes/sha2' +import type { ICryptoInterface } from '../crypto.js' +import type { KeyPair } from '../types.js' +import type { Uint8ArrayList } from 'uint8arraylist' + +export const pureJsCrypto: ICryptoInterface = { + hashSHA256 (data: Uint8Array | Uint8ArrayList): Uint8Array { + return sha256(data.subarray()) + }, + + getHKDF (ck: Uint8Array, ikm: Uint8Array): [Uint8Array, Uint8Array, Uint8Array] { + const prk = extract(sha256, ikm, ck) + const okmU8Array = expand(sha256, prk, undefined, 96) + const okm = okmU8Array + + const k1 = okm.subarray(0, 32) + const k2 = okm.subarray(32, 64) + const k3 = okm.subarray(64, 96) + + return [k1, k2, k3] + }, + + generateX25519KeyPair (): KeyPair { + const secretKey = x25519.utils.randomSecretKey() + const publicKey = x25519.getPublicKey(secretKey) + + return { + publicKey, + privateKey: secretKey + } + }, + + generateX25519KeyPairFromSeed (seed: Uint8Array): KeyPair { + const publicKey = x25519.getPublicKey(seed) + + return { + publicKey, + privateKey: seed + } + }, + + generateX25519SharedKey (privateKey: Uint8Array | Uint8ArrayList, publicKey: Uint8Array | Uint8ArrayList): Uint8Array { + return x25519.getSharedSecret(privateKey.subarray(), publicKey.subarray()) + }, + + chaCha20Poly1305Encrypt (plaintext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array): Uint8Array { + return chacha20poly1305(k, nonce, ad).encrypt(plaintext.subarray()) + }, + + chaCha20Poly1305Decrypt (ciphertext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array, dst?: Uint8Array): Uint8Array { + return chacha20poly1305(k, nonce, ad).decrypt(ciphertext.subarray(), dst) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/encoder.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/encoder.ts new file mode 100644 index 000000000..cbc2741eb --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/encoder.ts @@ -0,0 +1,24 @@ +import { allocUnsafe as uint8ArrayAllocUnsafe } from 'uint8arrays/alloc' +import type { Uint8ArrayList } from 'uint8arraylist' + +export const uint16BEEncode = (value: number): Uint8Array => { + const target = uint8ArrayAllocUnsafe(2) + target[0] = value >> 8 + target[1] = value + return target +} +uint16BEEncode.bytes = 2 + +export const uint16BEDecode = (data: Uint8Array | Uint8ArrayList): number => { + if (data.length < 2) { throw RangeError('Could not decode int16BE') } + + if (data instanceof Uint8Array) { + let value = 0 + value += data[0] << 8 + value += data[1] + return value + } + + return data.getUint16(0) +} +uint16BEDecode.bytes = 2 diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/errors.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/errors.ts new file mode 100644 index 000000000..6d526dae0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/errors.ts @@ -0,0 +1,10 @@ +export class InvalidCryptoExchangeError extends Error { + public code: string + + constructor (message = 'Invalid crypto exchange') { + super(message) + this.code = InvalidCryptoExchangeError.code + } + + static readonly code = 'ERR_INVALID_CRYPTO_EXCHANGE' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/index.ts new file mode 100644 index 000000000..3d288b0dc --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/index.ts @@ -0,0 +1,58 @@ +/** + * @packageDocumentation + * + * This repository contains TypeScript implementation of noise protocol, an encryption protocol used in libp2p. + * + * ## Usage + * + * Install with `yarn add @chainsafe/libp2p-noise` or `npm i @chainsafe/libp2p-noise`. + * + * Example of using default noise configuration and passing it to the libp2p config: + * + * ```ts + * import {createLibp2p} from "libp2p" + * import {noise} from "@chainsafe/libp2p-noise" + * + * //custom noise configuration, pass it instead of `noise()` + * //x25519 private key + * const n = noise({ staticNoiseKey }); + * + * const libp2p = await createLibp2p({ + * connectionEncrypters: [noise()], + * //... other options + * }) + * ``` + * + * See the [NoiseInit](https://github.com/ChainSafe/js-libp2p-noise/blob/master/src/noise.ts#L22-L30) interface for noise configuration options. + * + * ## API + * + * This module exposes an implementation of the [ConnectionEncrypter](https://libp2p.github.io/js-libp2p/interfaces/_libp2p_interface.ConnectionEncrypter.html) interface. + * + * ## Bring your own crypto + * + * You can provide a custom crypto implementation (instead of the default, based on [@noble](https://paulmillr.com/noble/)) by adding a `crypto` field to the init argument passed to the `Noise` factory. + * + * The implementation must conform to the `ICryptoInterface`, defined in + */ + +import { Noise } from './noise.js' +import type { NoiseInit, NoiseExtensions } from './noise.js' +import type { KeyPair } from './types.js' +import type { ComponentLogger, ConnectionEncrypter, Metrics, PeerId, PrivateKey, Upgrader } from '@libp2p/interface' + +export { pureJsCrypto } from './crypto/js.js' +export type { ICryptoInterface } from './crypto.js' +export type { NoiseInit, NoiseExtensions, KeyPair } + +export interface NoiseComponents { + peerId: PeerId + privateKey: PrivateKey + logger: ComponentLogger + upgrader: Upgrader + metrics?: Metrics +} + +export function noise (init: NoiseInit = {}): (components: NoiseComponents) => ConnectionEncrypter { + return (components: NoiseComponents) => new Noise(components, init) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/logger.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/logger.ts new file mode 100644 index 000000000..6a0a00672 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/logger.ts @@ -0,0 +1,65 @@ +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { DUMP_SESSION_KEYS } from './constants.js' +import type { CipherState } from './protocol.js' +import type { KeyPair } from './types.js' +import type { Logger } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +export function logLocalStaticKeys (s: KeyPair | undefined, keyLogger: Logger): void { + if (!keyLogger.enabled || !DUMP_SESSION_KEYS) { + return + } + + if (s) { + keyLogger(`LOCAL_STATIC_PUBLIC_KEY ${uint8ArrayToString(s.publicKey, 'hex')}`) + keyLogger(`LOCAL_STATIC_PRIVATE_KEY ${uint8ArrayToString(s.privateKey, 'hex')}`) + } else { + keyLogger('Missing local static keys.') + } +} + +export function logLocalEphemeralKeys (e: KeyPair | undefined, keyLogger: Logger): void { + if (!keyLogger.enabled || !DUMP_SESSION_KEYS) { + return + } + + if (e) { + keyLogger(`LOCAL_PUBLIC_EPHEMERAL_KEY ${uint8ArrayToString(e.publicKey, 'hex')}`) + keyLogger(`LOCAL_PRIVATE_EPHEMERAL_KEY ${uint8ArrayToString(e.privateKey, 'hex')}`) + } else { + keyLogger('Missing local ephemeral keys.') + } +} + +export function logRemoteStaticKey (rs: Uint8Array | Uint8ArrayList | undefined, keyLogger: Logger): void { + if (!keyLogger.enabled || !DUMP_SESSION_KEYS) { + return + } + + if (rs) { + keyLogger(`REMOTE_STATIC_PUBLIC_KEY ${uint8ArrayToString(rs.subarray(), 'hex')}`) + } else { + keyLogger('Missing remote static public key.') + } +} + +export function logRemoteEphemeralKey (re: Uint8Array | Uint8ArrayList | undefined, keyLogger: Logger): void { + if (!keyLogger.enabled || !DUMP_SESSION_KEYS) { + return + } + + if (re) { + keyLogger(`REMOTE_EPHEMERAL_PUBLIC_KEY ${uint8ArrayToString(re.subarray(), 'hex')}`) + } else { + keyLogger('Missing remote ephemeral keys.') + } +} + +export function logCipherState (cs1: CipherState, cs2: CipherState, keyLogger: Logger): void { + if (!keyLogger.enabled || !DUMP_SESSION_KEYS) { + return + } + + keyLogger(`CIPHER_STATE_1 ${cs1.n.getUint64()} ${cs1.k && uint8ArrayToString(cs1.k, 'hex')}`) + keyLogger(`CIPHER_STATE_2 ${cs2.n.getUint64()} ${cs2.k && uint8ArrayToString(cs2.k, 'hex')}`) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/metrics.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/metrics.ts new file mode 100644 index 000000000..3733d4192 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/metrics.ts @@ -0,0 +1,32 @@ +import type { Counter, Metrics } from '@libp2p/interface' + +export type MetricsRegistry = Record + +export function registerMetrics (metrics: Metrics): MetricsRegistry { + return { + xxHandshakeSuccesses: metrics.registerCounter( + 'libp2p_noise_xxhandshake_successes_total', { + help: 'Total count of noise xxHandshakes successes_' + }), + + xxHandshakeErrors: metrics.registerCounter( + 'libp2p_noise_xxhandshake_error_total', { + help: 'Total count of noise xxHandshakes errors' + }), + + encryptedPackets: metrics.registerCounter( + 'libp2p_noise_encrypted_packets_total', { + help: 'Total count of noise encrypted packets successfully' + }), + + decryptedPackets: metrics.registerCounter( + 'libp2p_noise_decrypted_packets_total', { + help: 'Total count of noise decrypted packets' + }), + + decryptErrors: metrics.registerCounter( + 'libp2p_noise_decrypt_errors_total', { + help: 'Total count of noise decrypt errors' + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/noise.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/noise.ts new file mode 100644 index 000000000..c78938b93 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/noise.ts @@ -0,0 +1,237 @@ +import { publicKeyFromProtobuf } from '@libp2p/crypto/keys' +import { InvalidCryptoExchangeError, serviceCapabilities } from '@libp2p/interface' +import { peerIdFromPublicKey } from '@libp2p/peer-id' +import { lpStream } from '@libp2p/utils' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' +import { NOISE_MSG_MAX_LENGTH_BYTES } from './constants.js' +import { defaultCrypto } from './crypto/index.js' +import { wrapCrypto } from './crypto.js' +import { uint16BEDecode, uint16BEEncode } from './encoder.js' +import { registerMetrics } from './metrics.js' +import { performHandshakeInitiator, performHandshakeResponder } from './performHandshake.js' +import type { ICryptoInterface } from './crypto.js' +import type { NoiseComponents } from './index.js' +import type { MetricsRegistry } from './metrics.js' +import type { HandshakeResult, ICrypto, INoiseConnection, INoiseExtensions, KeyPair } from './types.js' +import type { MultiaddrConnection, SecuredConnection, PrivateKey, PublicKey, StreamMuxerFactory, SecureConnectionOptions, Logger, MessageStream } from '@libp2p/interface' +import type { LengthPrefixedStream } from '@libp2p/utils' +import { toMessageStream } from './utils.ts' + +export interface NoiseExtensions { + webtransportCerthashes: Uint8Array[] +} + +export interface NoiseInit { + /** + * x25519 private key, reuse for faster handshakes + */ + staticNoiseKey?: Uint8Array + extensions?: Partial + crypto?: ICryptoInterface + prologueBytes?: Uint8Array +} + +export class Noise implements INoiseConnection { + public protocol = '/noise' + public crypto: ICrypto + + private readonly prologue: Uint8Array + private readonly staticKey: KeyPair + private readonly extensions?: NoiseExtensions + private readonly metrics?: MetricsRegistry + private readonly components: NoiseComponents + private readonly log: Logger + + constructor (components: NoiseComponents, init: NoiseInit = {}) { + const { staticNoiseKey, extensions, crypto, prologueBytes } = init + const { metrics } = components + + this.components = components + this.log = components.logger.forComponent('libp2p:noise') + const _crypto = crypto ?? defaultCrypto + this.crypto = wrapCrypto(_crypto) + this.extensions = { + webtransportCerthashes: [], + ...extensions + } + this.metrics = metrics ? registerMetrics(metrics) : undefined + + if (staticNoiseKey) { + // accepts x25519 private key of length 32 + this.staticKey = _crypto.generateX25519KeyPairFromSeed(staticNoiseKey) + } else { + this.staticKey = _crypto.generateX25519KeyPair() + } + this.prologue = prologueBytes ?? uint8ArrayAlloc(0) + } + + readonly [Symbol.toStringTag] = '@chainsafe/libp2p-noise' + + readonly [serviceCapabilities]: string[] = [ + '@libp2p/connection-encryption', + '@chainsafe/libp2p-noise' + ] + + /** + * Encrypt outgoing data to the remote party (handshake as initiator) + * + * @param connection - streaming iterable duplex that will be encrypted + * @param options + * @param options.remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer + * @param options.signal - Used to abort the operation + */ + async secureOutbound (connection: Stream, options?: SecureConnectionOptions): Promise> { + const log = connection.log?.newScope('noise') ?? this.log + const wrappedConnection = lpStream(connection, { + lengthEncoder: uint16BEEncode, + lengthDecoder: uint16BEDecode, + maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES + }) + + const handshake = await this.performHandshakeInitiator( + wrappedConnection, + this.components.privateKey, + log, + options?.remotePeer?.publicKey, + options + ) + const publicKey = publicKeyFromProtobuf(handshake.payload.identityKey) + + return { + connection: toMessageStream(wrappedConnection.unwrap(), handshake, this.metrics), + remoteExtensions: handshake.payload.extensions, + remotePeer: peerIdFromPublicKey(publicKey), + streamMuxer: options?.skipStreamMuxerNegotiation === true ? undefined : this.getStreamMuxer(handshake.payload.extensions?.streamMuxers) + } + } + + private getStreamMuxer (protocols?: string[]): StreamMuxerFactory | undefined { + if (protocols == null || protocols.length === 0) { + return + } + + const streamMuxers = this.components.upgrader.getStreamMuxers() + + if (streamMuxers != null) { + for (const protocol of protocols) { + const streamMuxer = streamMuxers.get(protocol) + + if (streamMuxer != null) { + return streamMuxer + } + } + } + + if (protocols.length) { + throw new InvalidCryptoExchangeError('Early muxer negotiation was requested but the initiator and responder had no common muxers') + } + } + + /** + * Decrypt incoming data (handshake as responder). + * + * @param connection - streaming iterable duplex that will be encrypted + * @param options + * @param options.remotePeer - PeerId of the remote peer. Used to validate the integrity of the remote peer + * @param options.signal - Used to abort the operation + */ + async secureInbound (connection: Stream, options?: SecureConnectionOptions): Promise> { + const log = connection.log?.newScope('noise') ?? this.log + const wrappedConnection = lpStream(connection, { + lengthEncoder: uint16BEEncode, + lengthDecoder: uint16BEDecode, + maxDataLength: NOISE_MSG_MAX_LENGTH_BYTES + }) + + const handshake = await this.performHandshakeResponder( + wrappedConnection, + this.components.privateKey, + log, + options?.remotePeer?.publicKey, + options + ) + const publicKey = publicKeyFromProtobuf(handshake.payload.identityKey) + + return { + connection: toMessageStream(wrappedConnection.unwrap(), handshake, this.metrics), + remoteExtensions: handshake.payload.extensions, + remotePeer: peerIdFromPublicKey(publicKey), + streamMuxer: options?.skipStreamMuxerNegotiation === true ? undefined : this.getStreamMuxer(handshake.payload.extensions?.streamMuxers) + } + } + + /** + * Perform XX handshake as initiator. + */ + private async performHandshakeInitiator ( + connection: LengthPrefixedStream, + // TODO: pass private key in noise constructor via Components + privateKey: PrivateKey, + log: Logger, + remoteIdentityKey?: PublicKey, + options?: SecureConnectionOptions + ): Promise { + let result: HandshakeResult + const streamMuxers = options?.skipStreamMuxerNegotiation === true ? [] : [...this.components.upgrader.getStreamMuxers().keys()] + + try { + result = await performHandshakeInitiator({ + connection, + privateKey, + remoteIdentityKey, + log: log.newScope('xxhandshake'), + crypto: this.crypto, + prologue: this.prologue, + s: this.staticKey, + extensions: { + streamMuxers, + webtransportCerthashes: [], + ...this.extensions + } + }, options) + this.metrics?.xxHandshakeSuccesses.increment() + } catch (e: unknown) { + this.metrics?.xxHandshakeErrors.increment() + throw e + } + + return result + } + + /** + * Perform XX handshake as responder. + */ + private async performHandshakeResponder ( + connection: LengthPrefixedStream, + privateKey: PrivateKey, + log: Logger, + remoteIdentityKey?: PublicKey, + options?: SecureConnectionOptions + ): Promise { + let result: HandshakeResult + const streamMuxers = options?.skipStreamMuxerNegotiation === true ? [] : [...this.components.upgrader.getStreamMuxers().keys()] + + try { + result = await performHandshakeResponder({ + connection, + privateKey, + remoteIdentityKey, + log: log.newScope('xxhandshake'), + crypto: this.crypto, + prologue: this.prologue, + s: this.staticKey, + extensions: { + streamMuxers, + webtransportCerthashes: [], + ...this.extensions + } + }, options) + this.metrics?.xxHandshakeSuccesses.increment() + } catch (e: unknown) { + this.metrics?.xxHandshakeErrors.increment() + throw e + } + + return result + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/nonce.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/nonce.ts new file mode 100644 index 000000000..d27b8627c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/nonce.ts @@ -0,0 +1,49 @@ +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' + +export const MIN_NONCE = 0 +// For performance reasons, the nonce is represented as a JS `number` +// Although JS `number` can safely represent integers up to 2 ** 53 - 1, we choose to only use +// 4 bytes to store the data for performance reason. +// This is a slight deviation from the noise spec, which describes the max nonce as 2 ** 64 - 2 +// The effect is that this implementation will need a new handshake to be performed after fewer messages are exchanged than other implementations with full uint64 nonces. +// this MAX_NONCE is still a large number of messages, so the practical effect of this is negligible. +export const MAX_NONCE = 0xffffffff + +const ERR_MAX_NONCE = 'Cipherstate has reached maximum n, a new handshake must be performed' + +/** + * The nonce is an uint that's increased over time. + * Maintaining different representations help improve performance. + */ +export class Nonce { + private n: number + private readonly bytes: Uint8Array + private readonly view: DataView + + constructor (n = MIN_NONCE) { + this.n = n + this.bytes = uint8ArrayAlloc(12) + this.view = new DataView(this.bytes.buffer, this.bytes.byteOffset, this.bytes.byteLength) + this.view.setUint32(4, n, true) + } + + increment (): void { + this.n++ + // Even though we're treating the nonce as 8 bytes, RFC7539 specifies 12 bytes for a nonce. + this.view.setUint32(4, this.n, true) + } + + getBytes (): Uint8Array { + return this.bytes + } + + getUint64 (): number { + return this.n + } + + assertValue (): void { + if (this.n > MAX_NONCE) { + throw new Error(ERR_MAX_NONCE) + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/performHandshake.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/performHandshake.ts new file mode 100644 index 000000000..dc197ba97 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/performHandshake.ts @@ -0,0 +1,91 @@ +import { + logLocalStaticKeys, + logLocalEphemeralKeys, + logRemoteEphemeralKey, + logRemoteStaticKey, + logCipherState +} from './logger.js' +import { ZEROLEN, XXHandshakeState } from './protocol.js' +import { createHandshakePayload, decodeHandshakePayload } from './utils.js' +import type { HandshakeResult, HandshakeParams } from './types.js' +import type { AbortOptions } from '@libp2p/interface' + +export async function performHandshakeInitiator (init: HandshakeParams, options?: AbortOptions): Promise { + const { log, connection, crypto, privateKey, prologue, s, remoteIdentityKey, extensions } = init + + const payload = await createHandshakePayload(privateKey, s.publicKey, extensions) + const xx = new XXHandshakeState({ + crypto, + protocolName: 'Noise_XX_25519_ChaChaPoly_SHA256', + initiator: true, + prologue, + s + }) + + logLocalStaticKeys(xx.s, log) + log.trace('Stage 0 - Initiator starting to send first message.') + await connection.write(xx.writeMessageA(ZEROLEN), options) + log.trace('Stage 0 - Initiator finished sending first message.') + logLocalEphemeralKeys(xx.e, log) + + log.trace('Stage 1 - Initiator waiting to receive first message from responder...') + const plaintext = xx.readMessageB(await connection.read(options)) + log.trace('Stage 1 - Initiator received the message.') + logRemoteEphemeralKey(xx.re, log) + logRemoteStaticKey(xx.rs, log) + + log.trace("Initiator going to check remote's signature...") + const receivedPayload = await decodeHandshakePayload(plaintext, xx.rs, remoteIdentityKey) + log.trace('All good with the signature!') + + log.trace('Stage 2 - Initiator sending third handshake message.') + await connection.write(xx.writeMessageC(payload), options) + log.trace('Stage 2 - Initiator sent message with signed payload.') + + const [cs1, cs2] = xx.ss.split() + logCipherState(cs1, cs2, log) + + return { + payload: receivedPayload, + encrypt: (plaintext) => cs1.encryptWithAd(ZEROLEN, plaintext), + decrypt: (ciphertext, dst) => cs2.decryptWithAd(ZEROLEN, ciphertext, dst) + } +} + +export async function performHandshakeResponder (init: HandshakeParams, options?: AbortOptions): Promise { + const { log, connection, crypto, privateKey, prologue, s, remoteIdentityKey, extensions } = init + + const payload = await createHandshakePayload(privateKey, s.publicKey, extensions) + const xx = new XXHandshakeState({ + crypto, + protocolName: 'Noise_XX_25519_ChaChaPoly_SHA256', + initiator: false, + prologue, + s + }) + + logLocalStaticKeys(xx.s, log) + log.trace('Stage 0 - Responder waiting to receive first message.') + xx.readMessageA(await connection.read(options)) + log.trace('Stage 0 - Responder received first message.') + logRemoteEphemeralKey(xx.re, log) + + log.trace('Stage 1 - Responder sending out first message with signed payload and static key.') + await connection.write(xx.writeMessageB(payload), options) + log.trace('Stage 1 - Responder sent the second handshake message with signed payload.') + logLocalEphemeralKeys(xx.e, log) + + log.trace('Stage 2 - Responder waiting for third handshake message...') + const plaintext = xx.readMessageC(await connection.read(options)) + log.trace('Stage 2 - Responder received the message, finished handshake.') + const receivedPayload = await decodeHandshakePayload(plaintext, xx.rs, remoteIdentityKey) + + const [cs1, cs2] = xx.ss.split() + logCipherState(cs1, cs2, log) + + return { + payload: receivedPayload, + encrypt: (plaintext) => cs2.encryptWithAd(ZEROLEN, plaintext), + decrypt: (ciphertext, dst) => cs1.decryptWithAd(ZEROLEN, ciphertext, dst) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/proto/payload.proto b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/proto/payload.proto new file mode 100644 index 000000000..5ee549067 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/proto/payload.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; + +message NoiseExtensions { + repeated bytes webtransport_certhashes = 1; + repeated string stream_muxers = 2; +} + +message NoiseHandshakePayload { + bytes identity_key = 1; + bytes identity_sig = 2; + optional NoiseExtensions extensions = 4; +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/proto/payload.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/proto/payload.ts new file mode 100644 index 000000000..e5a79ff37 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/proto/payload.ts @@ -0,0 +1,170 @@ +import { decodeMessage, encodeMessage, MaxLengthError, message } from 'protons-runtime' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' +import type { Codec, DecodeOptions } from 'protons-runtime' +import type { Uint8ArrayList } from 'uint8arraylist' + +export interface NoiseExtensions { + webtransportCerthashes: Uint8Array[] + streamMuxers: string[] +} + +export namespace NoiseExtensions { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if (obj.webtransportCerthashes != null) { + for (const value of obj.webtransportCerthashes) { + w.uint32(10) + w.bytes(value) + } + } + + if (obj.streamMuxers != null) { + for (const value of obj.streamMuxers) { + w.uint32(18) + w.string(value) + } + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + webtransportCerthashes: [], + streamMuxers: [] + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + if (opts.limits?.webtransportCerthashes != null && obj.webtransportCerthashes.length === opts.limits.webtransportCerthashes) { + throw new MaxLengthError('Decode error - map field "webtransportCerthashes" had too many elements') + } + + obj.webtransportCerthashes.push(reader.bytes()) + break + } + case 2: { + if (opts.limits?.streamMuxers != null && obj.streamMuxers.length === opts.limits.streamMuxers) { + throw new MaxLengthError('Decode error - map field "streamMuxers" had too many elements') + } + + obj.streamMuxers.push(reader.string()) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }) + } + + return _codec + } + + export const encode = (obj: Partial): Uint8Array => { + return encodeMessage(obj, NoiseExtensions.codec()) + } + + export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): NoiseExtensions => { + return decodeMessage(buf, NoiseExtensions.codec(), opts) + } +} + +export interface NoiseHandshakePayload { + identityKey: Uint8Array + identitySig: Uint8Array + extensions?: NoiseExtensions +} + +export namespace NoiseHandshakePayload { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.identityKey != null && obj.identityKey.byteLength > 0)) { + w.uint32(10) + w.bytes(obj.identityKey) + } + + if ((obj.identitySig != null && obj.identitySig.byteLength > 0)) { + w.uint32(18) + w.bytes(obj.identitySig) + } + + if (obj.extensions != null) { + w.uint32(34) + NoiseExtensions.codec().encode(obj.extensions, w) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + identityKey: uint8ArrayAlloc(0), + identitySig: uint8ArrayAlloc(0) + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.identityKey = reader.bytes() + break + } + case 2: { + obj.identitySig = reader.bytes() + break + } + case 4: { + obj.extensions = NoiseExtensions.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.extensions + }) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }) + } + + return _codec + } + + export const encode = (obj: Partial): Uint8Array => { + return encodeMessage(obj, NoiseHandshakePayload.codec()) + } + + export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): NoiseHandshakePayload => { + return decodeMessage(buf, NoiseHandshakePayload.codec(), opts) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/protocol.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/protocol.ts new file mode 100644 index 000000000..a71ac3b17 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/protocol.ts @@ -0,0 +1,313 @@ +import { Uint8ArrayList } from 'uint8arraylist' +import { fromString as uint8ArrayFromString } from 'uint8arrays' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' +import { InvalidCryptoExchangeError } from './errors.js' +import { Nonce } from './nonce.js' +import type { ICipherState, ISymmetricState, IHandshakeState, KeyPair, ICrypto } from './types.js' + +// Code in this file is a direct translation of a subset of the noise protocol https://noiseprotocol.org/noise.html, +// agnostic to libp2p's usage of noise + +export const ZEROLEN = uint8ArrayAlloc(0) + +interface ICipherStateWithKey extends ICipherState { + k: Uint8Array +} + +export class CipherState implements ICipherState { + public k?: Uint8Array + public n: Nonce + private readonly crypto: ICrypto + + constructor (crypto: ICrypto, k: Uint8Array | undefined = undefined, n = 0) { + this.crypto = crypto + this.k = k + this.n = new Nonce(n) + } + + public hasKey (): this is ICipherStateWithKey { + return Boolean(this.k) + } + + public encryptWithAd (ad: Uint8Array, plaintext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList { + if (!this.hasKey()) { + return plaintext + } + + this.n.assertValue() + const e = this.crypto.encrypt(plaintext, this.n.getBytes(), ad, this.k) + this.n.increment() + + return e + } + + public decryptWithAd (ad: Uint8Array, ciphertext: Uint8Array | Uint8ArrayList, dst?: Uint8Array): Uint8Array | Uint8ArrayList { + if (!this.hasKey()) { + return ciphertext + } + + this.n.assertValue() + const plaintext = this.crypto.decrypt(ciphertext, this.n.getBytes(), ad, this.k, dst) + this.n.increment() + + return plaintext + } +} + +export class SymmetricState implements ISymmetricState { + public cs: CipherState + public ck: Uint8Array + public h: Uint8Array + private readonly crypto: ICrypto + + constructor (crypto: ICrypto, protocolName: string) { + this.crypto = crypto + + const protocolNameBytes = uint8ArrayFromString(protocolName, 'utf-8') + this.h = hashProtocolName(crypto, protocolNameBytes) + + this.ck = this.h + this.cs = new CipherState(crypto) + } + + public mixKey (ikm: Uint8Array): void { + const [ck, tempK] = this.crypto.hkdf(this.ck, ikm) + this.ck = ck + this.cs = new CipherState(this.crypto, tempK) + } + + public mixHash (data: Uint8Array | Uint8ArrayList): void { + this.h = this.crypto.hash(new Uint8ArrayList(this.h, data)) + } + + public encryptAndHash (plaintext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList { + const ciphertext = this.cs.encryptWithAd(this.h, plaintext) + this.mixHash(ciphertext) + return ciphertext + } + + public decryptAndHash (ciphertext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList { + const plaintext = this.cs.decryptWithAd(this.h, ciphertext) + this.mixHash(ciphertext) + return plaintext + } + + public split (): [CipherState, CipherState] { + const [tempK1, tempK2] = this.crypto.hkdf(this.ck, ZEROLEN) + return [new CipherState(this.crypto, tempK1), new CipherState(this.crypto, tempK2)] + } +} + +// const MESSAGE_PATTERNS = ['e', 's', 'ee', 'es', 'se', 'ss'] as const +// type MessagePattern = Array + +export interface HandshakeStateInit { + crypto: ICrypto + protocolName: string + initiator: boolean + prologue: Uint8Array + s?: KeyPair + e?: KeyPair + rs?: Uint8Array | Uint8ArrayList + re?: Uint8Array | Uint8ArrayList +} + +export abstract class AbstractHandshakeState implements IHandshakeState { + public ss: SymmetricState + public s?: KeyPair + public e?: KeyPair + public rs?: Uint8Array | Uint8ArrayList + public re?: Uint8Array | Uint8ArrayList + public initiator: boolean + protected readonly crypto: ICrypto + + constructor (init: HandshakeStateInit) { + const { crypto, protocolName, prologue, initiator, s, e, rs, re } = init + this.crypto = crypto + this.ss = new SymmetricState(crypto, protocolName) + this.ss.mixHash(prologue) + this.initiator = initiator + this.s = s + this.e = e + this.rs = rs + this.re = re + } + + protected writeE (): Uint8Array { + if (this.e) { + throw new Error('ephemeral keypair is already set') + } + const e = this.crypto.generateKeypair() + this.ss.mixHash(e.publicKey) + this.e = e + return e.publicKey + } + + protected writeS (): Uint8Array | Uint8ArrayList { + if (!this.s) { + throw new Error('static keypair is not set') + } + return this.ss.encryptAndHash(this.s.publicKey) + } + + protected writeEE (): void { + if (!this.e) { + throw new Error('ephemeral keypair is not set') + } + if (!this.re) { + throw new Error('remote ephemeral public key is not set') + } + this.ss.mixKey(this.crypto.dh(this.e, this.re)) + } + + protected writeES (): void { + if (this.initiator) { + if (!this.e) { + throw new Error('ephemeral keypair is not set') + } + if (!this.rs) { + throw new Error('remote static public key is not set') + } + this.ss.mixKey(this.crypto.dh(this.e, this.rs)) + } else { + if (!this.s) { + throw new Error('static keypair is not set') + } + if (!this.re) { + throw new Error('remote ephemeral public key is not set') + } + this.ss.mixKey(this.crypto.dh(this.s, this.re)) + } + } + + protected writeSE (): void { + if (this.initiator) { + if (!this.s) { + throw new Error('static keypair is not set') + } + if (!this.re) { + throw new Error('remote ephemeral public key is not set') + } + this.ss.mixKey(this.crypto.dh(this.s, this.re)) + } else { + if (!this.e) { + throw new Error('ephemeral keypair is not set') + } + if (!this.rs) { + throw new Error('remote static public key is not set') + } + this.ss.mixKey(this.crypto.dh(this.e, this.rs)) + } + } + + protected readE (message: Uint8ArrayList, offset = 0): void { + if (this.re) { + throw new Error('remote ephemeral public key is already set') + } + if (message.byteLength < offset + 32) { + throw new Error('message is not long enough') + } + this.re = message.sublist(offset, offset + 32) + this.ss.mixHash(this.re) + } + + protected readS (message: Uint8ArrayList, offset = 0): number { + if (this.rs) { + throw new Error('remote static public key is already set') + } + const cipherLength = 32 + (this.ss.cs.hasKey() ? 16 : 0) + if (message.byteLength < offset + cipherLength) { + throw new Error('message is not long enough') + } + const temp = message.sublist(offset, offset + cipherLength) + this.rs = this.ss.decryptAndHash(temp) + return cipherLength + } + + protected readEE (): void { + this.writeEE() + } + + protected readES (): void { + this.writeES() + } + + protected readSE (): void { + this.writeSE() + } +} + +/** + * A IHandshakeState that's optimized for the XX pattern + */ +export class XXHandshakeState extends AbstractHandshakeState { + // e + writeMessageA (payload: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList { + return new Uint8ArrayList(this.writeE(), this.ss.encryptAndHash(payload)) + } + + // e, ee, s, es + writeMessageB (payload: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList { + const e = this.writeE() + this.writeEE() + const encS = this.writeS() + this.writeES() + + return new Uint8ArrayList(e, encS, this.ss.encryptAndHash(payload)) + } + + // s, se + writeMessageC (payload: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList { + const encS = this.writeS() + this.writeSE() + + return new Uint8ArrayList(encS, this.ss.encryptAndHash(payload)) + } + + // e + readMessageA (message: Uint8ArrayList): Uint8Array | Uint8ArrayList { + try { + this.readE(message) + + return this.ss.decryptAndHash(message.sublist(32)) + } catch (e) { + throw new InvalidCryptoExchangeError(`handshake stage 0 validation fail: ${(e as Error).message}`) + } + } + + // e, ee, s, es + readMessageB (message: Uint8ArrayList): Uint8Array | Uint8ArrayList { + try { + this.readE(message) + this.readEE() + const consumed = this.readS(message, 32) + this.readES() + + return this.ss.decryptAndHash(message.sublist(32 + consumed)) + } catch (e) { + throw new InvalidCryptoExchangeError(`handshake stage 1 validation fail: ${(e as Error).message}`) + } + } + + // s, se + readMessageC (message: Uint8ArrayList): Uint8Array | Uint8ArrayList { + try { + const consumed = this.readS(message) + this.readSE() + + return this.ss.decryptAndHash(message.sublist(consumed)) + } catch (e) { + throw new InvalidCryptoExchangeError(`handshake stage 2 validation fail: ${(e as Error).message}`) + } + } +} + +function hashProtocolName (crypto: ICrypto, protocolName: Uint8Array): Uint8Array { + if (protocolName.length <= 32) { + const h = uint8ArrayAlloc(32) + h.set(protocolName) + return h + } else { + return crypto.hash(protocolName) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/streaming.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/streaming.ts new file mode 100644 index 000000000..f7e2b7f74 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/streaming.ts @@ -0,0 +1,67 @@ +import { Uint8ArrayList } from 'uint8arraylist' +import { NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG } from './constants.js' +import { uint16BEEncode } from './encoder.js' +import type { MetricsRegistry } from './metrics.js' +import type { HandshakeResult } from './types.js' +import type { Transform } from 'it-stream-types' + +const CHACHA_TAG_LENGTH = 16 + +// Returns generator that encrypts payload from the user +export function encryptStream (handshake: HandshakeResult, metrics?: MetricsRegistry): Transform> { + return async function * (source) { + for await (const chunk of source) { + for (let i = 0; i < chunk.length; i += NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG) { + let end = i + NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG + if (end > chunk.length) { + end = chunk.length + } + + let data: Uint8Array | Uint8ArrayList + + if (chunk instanceof Uint8Array) { + data = handshake.encrypt(chunk.subarray(i, end)) + } else { + data = handshake.encrypt(chunk.sublist(i, end)) + } + + metrics?.encryptedPackets.increment() + + yield new Uint8ArrayList(uint16BEEncode(data.byteLength), data) + } + } + } +} + +// Decrypt received payload to the user +export function decryptStream (handshake: HandshakeResult, metrics?: MetricsRegistry): Transform, AsyncGenerator> { + return async function * (source) { + for await (const chunk of source) { + for (let i = 0; i < chunk.length; i += NOISE_MSG_MAX_LENGTH_BYTES) { + let end = i + NOISE_MSG_MAX_LENGTH_BYTES + if (end > chunk.length) { + end = chunk.length + } + + if (end - CHACHA_TAG_LENGTH < i) { + throw new Error('Invalid chunk') + } + + const encrypted = chunk.sublist(i, end) + // memory allocation is not cheap so reuse the encrypted Uint8Array + // see https://github.com/ChainSafe/js-libp2p-noise/pull/242#issue-1422126164 + // this is ok because chacha20 reads bytes one by one and don't reread after that + // it's also tested in https://github.com/ChainSafe/as-chacha20poly1305/pull/1/files#diff-25252846b58979dcaf4e41d47b3eadd7e4f335e7fb98da6c049b1f9cd011f381R48 + const dst = chunk.subarray(i, end - CHACHA_TAG_LENGTH) + try { + const plaintext = handshake.decrypt(encrypted, dst) + metrics?.decryptedPackets.increment() + yield plaintext + } catch (e) { + metrics?.decryptErrors.increment() + throw e + } + } + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/types.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/types.ts new file mode 100644 index 000000000..e7080f179 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/types.ts @@ -0,0 +1,88 @@ +import type { Nonce } from './nonce.js' +import type { NoiseExtensions, NoiseHandshakePayload } from './proto/payload.js' +import type { ConnectionEncrypter, Logger, PrivateKey, PublicKey } from '@libp2p/interface' +import type { LengthPrefixedStream } from '@libp2p/utils' +import type { Uint8ArrayList } from 'uint8arraylist' + +/** Crypto functions defined by the noise protocol, abstracted from the underlying implementations */ +export interface ICrypto { + generateKeypair(): KeyPair + dh(keypair: KeyPair, publicKey: Uint8Array | Uint8ArrayList): Uint8Array + encrypt(plaintext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array): Uint8ArrayList | Uint8Array + decrypt(ciphertext: Uint8Array | Uint8ArrayList, nonce: Uint8Array, ad: Uint8Array, k: Uint8Array, dst?: Uint8Array): Uint8ArrayList | Uint8Array + hash(data: Uint8Array | Uint8ArrayList): Uint8Array + hkdf(ck: Uint8Array, ikm: Uint8Array): [Uint8Array, Uint8Array, Uint8Array] +} + +export interface HandshakeParams { + log: Logger + connection: LengthPrefixedStream + crypto: ICrypto + privateKey: PrivateKey + prologue: Uint8Array + /** static keypair */ + s: KeyPair + remoteIdentityKey?: PublicKey + extensions?: NoiseExtensions +} + +export interface HandshakeResult { + payload: NoiseHandshakePayload + encrypt (plaintext: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList + decrypt (ciphertext: Uint8Array | Uint8ArrayList, dst?: Uint8Array): Uint8Array | Uint8ArrayList +} + +/** + * A CipherState object contains k and n variables, which it uses to encrypt and decrypt ciphertexts. + * During the handshake phase each party has a single CipherState, but during the transport phase each party has two CipherState objects: one for sending, and one for receiving. + */ +export interface ICipherState { + /** A cipher key of 32 bytes (which may be empty). Empty is a special value which indicates k has not yet been initialized. */ + k?: Uint8Array + /** + * An 8-byte (64-bit) unsigned integer nonce. + * + * For performance reasons, the nonce is represented as a Nonce object + * The nonce is treated as a uint64, even though the underlying `number` only has 52 safely-available bits. + */ + n: Nonce +} + +/** + * A SymmetricState object contains a CipherState plus ck and h variables. It is so-named because it encapsulates all the "symmetric crypto" used by Noise. + * During the handshake phase each party has a single SymmetricState, which can be deleted once the handshake is finished. + */ +export interface ISymmetricState { + cs: ICipherState + /** A chaining key of 32 bytes. */ + ck: Uint8Array + /** A hash output of 32 bytes. */ + h: Uint8Array +} + +/** + * A HandshakeState object contains a SymmetricState plus DH variables (s, e, rs, re) and a variable representing the handshake pattern. + * During the handshake phase each party has a single HandshakeState, which can be deleted once the handshake is finished. + */ +export interface IHandshakeState { + ss: ISymmetricState + /** The local static key pair */ + s?: KeyPair + /** The local ephemeral key pair */ + e?: KeyPair + /** The remote party's static public key */ + rs?: Uint8Array | Uint8ArrayList + /** The remote party's ephemeral public key */ + re?: Uint8Array | Uint8ArrayList +} + +export interface KeyPair { + publicKey: Uint8Array + privateKey: Uint8Array +} + +export interface INoiseExtensions { + webtransportCerthashes: Uint8Array[] +} + +export interface INoiseConnection extends ConnectionEncrypter { } diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/utils.ts new file mode 100644 index 000000000..aa07337ec --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/src/utils.ts @@ -0,0 +1,224 @@ +import { publicKeyFromProtobuf, publicKeyToProtobuf } from '@libp2p/crypto/keys' +import { StreamMessageEvent, UnexpectedPeerError } from '@libp2p/interface' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { NoiseHandshakePayload } from './proto/payload.js' +import type { NoiseExtensions } from './proto/payload.js' +import type { AbortOptions, MessageStream, PrivateKey, PublicKey } from '@libp2p/interface' +import { Uint8ArrayList } from 'uint8arraylist' +import { AbstractMessageStream, LengthPrefixedDecoder, type SendResult } from '@libp2p/utils' +import type { HandshakeResult } from './types.ts' +import { CHACHA_TAG_LENGTH, NOISE_MSG_MAX_LENGTH_BYTES, NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG } from './constants.ts' +import type { MetricsRegistry } from './metrics.ts' +import { uint16BEEncode, uint16BEDecode } from './encoder.ts' + +export async function createHandshakePayload ( + privateKey: PrivateKey, + staticPublicKey: Uint8Array | Uint8ArrayList, + extensions?: NoiseExtensions +): Promise { + const identitySig = await privateKey.sign(getSignaturePayload(staticPublicKey)) + + return NoiseHandshakePayload.encode({ + identityKey: publicKeyToProtobuf(privateKey.publicKey), + identitySig, + extensions + }) +} + +export async function decodeHandshakePayload ( + payloadBytes: Uint8Array | Uint8ArrayList, + remoteStaticKey?: Uint8Array | Uint8ArrayList, + remoteIdentityKey?: PublicKey +): Promise { + try { + const payload = NoiseHandshakePayload.decode(payloadBytes) + const publicKey = publicKeyFromProtobuf(payload.identityKey) + + if (remoteIdentityKey?.equals(publicKey) === false) { + throw new Error(`Payload identity key ${publicKey} does not match expected remote identity key ${remoteIdentityKey}`) + } + + if (!remoteStaticKey) { + throw new Error('Remote static does not exist') + } + + const signaturePayload = getSignaturePayload(remoteStaticKey) + + if (!(await publicKey.verify(signaturePayload, payload.identitySig))) { + throw new Error('Invalid payload signature') + } + + return payload + } catch (e) { + throw new UnexpectedPeerError((e as Error).message) + } +} + +export function getSignaturePayload (publicKey: Uint8Array | Uint8ArrayList): Uint8Array | Uint8ArrayList { + const prefix = uint8ArrayFromString('noise-libp2p-static-key:') + + if (publicKey instanceof Uint8Array) { + return uint8ArrayConcat([prefix, publicKey], prefix.length + publicKey.length) + } + + publicKey.prepend(prefix) + + return publicKey +} + +class EncryptedMessageStream extends AbstractMessageStream { + private stream: MessageStream + private handshake: HandshakeResult + private metrics?: MetricsRegistry + private decoder: LengthPrefixedDecoder + + constructor (stream: MessageStream, handshake: HandshakeResult, metrics?: MetricsRegistry) { + super({ + log: stream.log, + inactivityTimeout: stream.inactivityTimeout, + maxPauseBufferLength: stream.maxPauseBufferLength, + direction: stream.direction + }) + + this.stream = stream + this.handshake = handshake + this.metrics = metrics + this.decoder = new LengthPrefixedDecoder({ + lengthDecoder: uint16BEDecode, + encodingLength: () => 2 + }) + + this.stream.addEventListener('message', (evt) => { + try { + for (const buf of this.decoder.decode(evt.data)) { + const decrypted = this.decrypt(buf) + this.dispatchEvent(new StreamMessageEvent(decrypted)) + } + } catch (err: any) { + this.abort(err) + } + }) + + this.stream.addEventListener('close', (evt) => { + if (evt.error != null) { + if (evt.local === true) { + this.abort(evt.error) + } else { + this.onRemoteReset() + } + } else { + this.onClosed() + } + }) + + this.stream.addEventListener('drain', () => { + this.safeDispatchEvent('drain') + }) + + this.stream.addEventListener('remoteCloseWrite', () => { + this.onRemoteCloseWrite() + }) + + this.stream.addEventListener('remoteCloseRead', () => { + this.onRemoteCloseRead() + }) + } + + encrypt (chunk: Uint8Array | Uint8ArrayList): Uint8ArrayList { + const output = new Uint8ArrayList() + + for (let i = 0; i < chunk.byteLength; i += NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG) { + let end = i + NOISE_MSG_MAX_LENGTH_BYTES_WITHOUT_TAG + if (end > chunk.byteLength) { + end = chunk.byteLength + } + + let data: Uint8Array | Uint8ArrayList + + if (chunk instanceof Uint8Array) { + data = this.handshake.encrypt(chunk.subarray(i, end)) + } else { + data = this.handshake.encrypt(chunk.sublist(i, end)) + } + + this.metrics?.encryptedPackets.increment() + + output.append(uint16BEEncode(data.byteLength)) + output.append(data) + } + + return output + } + + decrypt (chunk: Uint8Array | Uint8ArrayList): Uint8ArrayList { + const output = new Uint8ArrayList() + + for (let i = 0; i < chunk.byteLength; i += NOISE_MSG_MAX_LENGTH_BYTES) { + let end = i + NOISE_MSG_MAX_LENGTH_BYTES + if (end > chunk.byteLength) { + end = chunk.byteLength + } + + if (end - CHACHA_TAG_LENGTH < i) { + throw new Error('Invalid chunk') + } + + let encrypted: Uint8Array | Uint8ArrayList + + if (chunk instanceof Uint8Array) { + encrypted = chunk.subarray(i, end) + } else { + encrypted = chunk.sublist(i, end) + } + + // memory allocation is not cheap so reuse the encrypted Uint8Array + // see https://github.com/ChainSafe/js-libp2p-noise/pull/242#issue-1422126164 + // this is ok because chacha20 reads bytes one by one and don't reread after that + // it's also tested in https://github.com/ChainSafe/as-chacha20poly1305/pull/1/files#diff-25252846b58979dcaf4e41d47b3eadd7e4f335e7fb98da6c049b1f9cd011f381R48 + const dst = chunk.subarray(i, end - CHACHA_TAG_LENGTH) + try { + const plaintext = this.handshake.decrypt(encrypted, dst) + this.metrics?.decryptedPackets.increment() + + output.append(plaintext) + } catch (e) { + this.metrics?.decryptErrors.increment() + throw e + } + } + + return output + } + + sendPause (): void { + this.stream.pause() + } + + sendResume (): void { + this.stream.resume() + } + + async sendCloseWrite (options?: AbortOptions): Promise { + return this.stream.closeWrite(options) + } + + async sendCloseRead (options?: AbortOptions): Promise { + return this.stream.closeRead(options) + } + + sendReset (err: Error): void { + this.stream.abort(err) + } + + sendData (data: Uint8ArrayList): SendResult { + return { + sentBytes: data.byteLength, + canSendMore: this.stream.send(this.encrypt(data)) + } + } +} + +export function toMessageStream (connection: MessageStream, handshake: HandshakeResult, metrics?: MetricsRegistry): MessageStream { + return new EncryptedMessageStream(connection, handshake, metrics) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/connection-encrypter-noise/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/.aegir.js b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/.aegir.js new file mode 100644 index 000000000..3cda4fd78 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/.aegir.js @@ -0,0 +1,7 @@ + +/** @type {import('aegir/types').PartialOptions} */ +export default { + build: { + bundlesizeMax: '70kB' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/README.md new file mode 100644 index 000000000..362920470 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/README.md @@ -0,0 +1,60 @@ +# @libp2p/crypto + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> Crypto primitives for libp2p + +# About + + + +The `libp2p-crypto` library depends on the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) in the browser. Web Crypto is available in all modern browsers, however browsers restrict its usage to [Secure Contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts). + +This means you will not be able to use some `@libp2p/crypto` functions in the browser when the page is served over HTTP.\* + +To enable the Web Crypto API and allow `@libp2p/crypto` to work fully, please serve your page over HTTPS. + +# Install + +```console +$ npm i @libp2p/crypto +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/crypto/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/crypto/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/package.json new file mode 100644 index 000000000..3f0d229e7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/package.json @@ -0,0 +1,106 @@ +{ + "name": "@libp2p/crypto", + "version": "5.1.7", + "description": "Crypto primitives for libp2p", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/crypto#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "IPFS", + "crypto", + "libp2p", + "rsa", + "secp256k1" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "typesVersions": { + "*": { + "*": [ + "*", + "dist/*", + "dist/src/*", + "dist/src/*/index" + ], + "src/*": [ + "*", + "dist/*", + "dist/src/*", + "dist/src/*/index" + ] + } + }, + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + }, + "./ciphers": { + "types": "./dist/src/ciphers/index.d.ts", + "import": "./dist/src/ciphers/index.js" + }, + "./hmac": { + "types": "./dist/src/hmac/index.d.ts", + "import": "./dist/src/hmac/index.js" + }, + "./keys": { + "types": "./dist/src/keys/index.d.ts", + "import": "./dist/src/keys/index.js" + }, + "./webcrypto": { + "types": "./dist/src/webcrypto/index.d.ts", + "import": "./dist/src/webcrypto/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build", + "test": "aegir test", + "test:chrome": "aegir test -t browser", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "generate": "protons ./src/keys/keys.proto" + }, + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@noble/curves": "^1.9.1", + "@noble/hashes": "^1.8.0", + "multiformats": "^13.3.6", + "protons-runtime": "^5.5.0", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + }, + "browser": { + "./dist/src/ciphers/aes-gcm.js": "./dist/src/ciphers/aes-gcm.browser.js", + "./dist/src/hmac/index.js": "./dist/src/hmac/index.browser.js", + "./dist/src/keys/ecdh/index.js": "./dist/src/keys/ecdh/index.browser.js", + "./dist/src/keys/ed25519/index.js": "./dist/src/keys/ed25519/index.browser.js", + "./dist/src/keys/rsa/index.js": "./dist/src/keys/rsa/index.browser.js", + "./dist/src/keys/secp256k1/index.js": "./dist/src/keys/secp256k1/index.browser.js", + "./dist/src/webcrypto/webcrypto.js": "./dist/src/webcrypto/webcrypto.browser.js" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/aes-gcm.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/aes-gcm.browser.ts new file mode 100644 index 000000000..bc0abf26c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/aes-gcm.browser.ts @@ -0,0 +1,116 @@ +import { concat } from 'uint8arrays/concat' +import { fromString } from 'uint8arrays/from-string' +import webcrypto from '../webcrypto/index.js' +import type { CreateAESCipherOptions, AESCipher } from './interface.js' + +// WebKit on Linux does not support deriving a key from an empty PBKDF2 key. +// So, as a workaround, we provide the generated key as a constant. We test that +// this generated key is accurate in test/workaround.spec.ts +// Generated via: +// await crypto.subtle.exportKey('jwk', +// await crypto.subtle.deriveKey( +// { name: 'PBKDF2', salt: new Uint8Array(16), iterations: 32767, hash: { name: 'SHA-256' } }, +// await crypto.subtle.importKey('raw', new Uint8Array(0), { name: 'PBKDF2' }, false, ['deriveKey']), +// { name: 'AES-GCM', length: 128 }, true, ['encrypt', 'decrypt']) +// ) +export const derivedEmptyPasswordKey = { + alg: 'A128GCM', + ext: true, + /* spell-checker:disable-next-line */ + k: 'scm9jmO_4BJAgdwWGVulLg', + key_ops: ['encrypt', 'decrypt'], + kty: 'oct' +} + +// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples + +export function create (opts?: CreateAESCipherOptions): AESCipher { + const algorithm = opts?.algorithm ?? 'AES-GCM' + let keyLength = opts?.keyLength ?? 16 + const nonceLength = opts?.nonceLength ?? 12 + const digest = opts?.digest ?? 'SHA-256' + const saltLength = opts?.saltLength ?? 16 + const iterations = opts?.iterations ?? 32767 + + const crypto = webcrypto.get() + keyLength *= 8 // Browser crypto uses bits instead of bytes + + /** + * Uses the provided password to derive a pbkdf2 key. The key + * will then be used to encrypt the data. + */ + async function encrypt (data: Uint8Array, password: string | Uint8Array): Promise { + const salt = crypto.getRandomValues(new Uint8Array(saltLength)) + const nonce = crypto.getRandomValues(new Uint8Array(nonceLength)) + const aesGcm = { name: algorithm, iv: nonce } + + if (typeof password === 'string') { + password = fromString(password) + } + + let cryptoKey: CryptoKey + if (password.length === 0) { + cryptoKey = await crypto.subtle.importKey('jwk', derivedEmptyPasswordKey, { name: 'AES-GCM' }, true, ['encrypt']) + try { + const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } + const runtimeDerivedEmptyPassword = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveKey']) + cryptoKey = await crypto.subtle.deriveKey(deriveParams, runtimeDerivedEmptyPassword, { name: algorithm, length: keyLength }, true, ['encrypt']) + } catch { + cryptoKey = await crypto.subtle.importKey('jwk', derivedEmptyPasswordKey, { name: 'AES-GCM' }, true, ['encrypt']) + } + } else { + // Derive a key using PBKDF2. + const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } + const rawKey = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveKey']) + cryptoKey = await crypto.subtle.deriveKey(deriveParams, rawKey, { name: algorithm, length: keyLength }, true, ['encrypt']) + } + + // Encrypt the string. + const ciphertext = await crypto.subtle.encrypt(aesGcm, cryptoKey, data) + return concat([salt, aesGcm.iv, new Uint8Array(ciphertext)]) + } + + /** + * Uses the provided password to derive a pbkdf2 key. The key + * will then be used to decrypt the data. The options used to create + * this decryption cipher must be the same as those used to create + * the encryption cipher. + */ + async function decrypt (data: Uint8Array, password: string | Uint8Array): Promise { + const salt = data.subarray(0, saltLength) + const nonce = data.subarray(saltLength, saltLength + nonceLength) + const ciphertext = data.subarray(saltLength + nonceLength) + const aesGcm = { name: algorithm, iv: nonce } + + if (typeof password === 'string') { + password = fromString(password) + } + + let cryptoKey: CryptoKey + if (password.length === 0) { + try { + const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } + const runtimeDerivedEmptyPassword = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveKey']) + cryptoKey = await crypto.subtle.deriveKey(deriveParams, runtimeDerivedEmptyPassword, { name: algorithm, length: keyLength }, true, ['decrypt']) + } catch { + cryptoKey = await crypto.subtle.importKey('jwk', derivedEmptyPasswordKey, { name: 'AES-GCM' }, true, ['decrypt']) + } + } else { + // Derive the key using PBKDF2. + const deriveParams = { name: 'PBKDF2', salt, iterations, hash: { name: digest } } + const rawKey = await crypto.subtle.importKey('raw', password, { name: 'PBKDF2' }, false, ['deriveKey']) + cryptoKey = await crypto.subtle.deriveKey(deriveParams, rawKey, { name: algorithm, length: keyLength }, true, ['decrypt']) + } + + // Decrypt the string. + const plaintext = await crypto.subtle.decrypt(aesGcm, cryptoKey, ciphertext) + return new Uint8Array(plaintext) + } + + const cipher: AESCipher = { + encrypt, + decrypt + } + + return cipher +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/aes-gcm.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/aes-gcm.ts new file mode 100644 index 000000000..9aeb4a7e5 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/aes-gcm.ts @@ -0,0 +1,104 @@ +import crypto from 'crypto' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import type { CreateAESCipherOptions, AESCipher } from './interface.js' + +export type { AESCipher, CreateAESCipherOptions } + +// Based off of code from https://github.com/luke-park/SecureCompatibleEncryptionExamples + +export function create (opts?: CreateAESCipherOptions): AESCipher { + const algorithm = opts?.algorithm ?? 'aes-128-gcm' + const keyLength = opts?.keyLength ?? 16 + const nonceLength = opts?.nonceLength ?? 12 + const digest = opts?.digest ?? 'sha256' + const saltLength = opts?.saltLength ?? 16 + const iterations = opts?.iterations ?? 32767 + const algorithmTagLength = opts?.algorithmTagLength ?? 16 + + function encryptWithKey (data: Uint8Array, key: Uint8Array): Uint8Array { + const nonce = crypto.randomBytes(nonceLength) + + // Create the cipher instance. + const cipher = crypto.createCipheriv(algorithm, key, nonce) + + // Encrypt and prepend nonce. + const ciphertext = uint8ArrayConcat([cipher.update(data), cipher.final()]) + + // @ts-expect-error getAuthTag is not a function + return uint8ArrayConcat([nonce, ciphertext, cipher.getAuthTag()]) + } + + /** + * Uses the provided password to derive a pbkdf2 key. The key + * will then be used to encrypt the data. + */ + async function encrypt (data: Uint8Array, password: string | Uint8Array): Promise { + // Generate a 128-bit salt + const salt = crypto.randomBytes(saltLength) + + if (typeof password === 'string') { + password = uint8ArrayFromString(password) + } + + // Derive a key using PBKDF2. + const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest) + + // Encrypt and prepend salt. + return uint8ArrayConcat([salt, encryptWithKey(Uint8Array.from(data), key)]) + } + + /** + * Decrypts the given cipher text with the provided key. The `key` should + * be a cryptographically safe key and not a plaintext password. To use + * a plaintext password, use `decrypt`. The options used to create + * this decryption cipher must be the same as those used to create + * the encryption cipher. + */ + function decryptWithKey (ciphertextAndNonce: Uint8Array, key: Uint8Array): Uint8Array { + // Create Uint8Arrays of nonce, ciphertext and tag. + const nonce = ciphertextAndNonce.subarray(0, nonceLength) + const ciphertext = ciphertextAndNonce.subarray(nonceLength, ciphertextAndNonce.length - algorithmTagLength) + const tag = ciphertextAndNonce.subarray(ciphertext.length + nonceLength) + + // Create the cipher instance. + const cipher = crypto.createDecipheriv(algorithm, key, nonce) + + // Decrypt and return result. + // @ts-expect-error getAuthTag is not a function + cipher.setAuthTag(tag) + return uint8ArrayConcat([cipher.update(ciphertext), cipher.final()]) + } + + /** + * Uses the provided password to derive a pbkdf2 key. The key + * will then be used to decrypt the data. The options used to create + * this decryption cipher must be the same as those used to create + * the encryption cipher. + * + * @param {Uint8Array} data - The data to decrypt + * @param {string|Uint8Array} password - A plain password + */ + async function decrypt (data: Uint8Array, password: string | Uint8Array): Promise { + // Create Uint8Arrays of salt and ciphertextAndNonce. + const salt = data.subarray(0, saltLength) + const ciphertextAndNonce = data.subarray(saltLength) + + if (typeof password === 'string') { + password = uint8ArrayFromString(password) + } + + // Derive the key using PBKDF2. + const key = crypto.pbkdf2Sync(password, salt, iterations, keyLength, digest) + + // Decrypt and return result. + return decryptWithKey(ciphertextAndNonce, key) + } + + const cipher: AESCipher = { + encrypt, + decrypt + } + + return cipher +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/index.ts new file mode 100644 index 000000000..a5ae5ecd1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/index.ts @@ -0,0 +1 @@ +export * as AES_GCM from './aes-gcm.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/interface.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/interface.ts new file mode 100644 index 000000000..4ad94d3c3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/ciphers/interface.ts @@ -0,0 +1,14 @@ +export interface CreateAESCipherOptions { + algorithm?: string + nonceLength?: number + keyLength?: number + digest?: string + saltLength?: number + iterations?: number + algorithmTagLength?: number +} + +export interface AESCipher { + encrypt(data: Uint8Array, password: string | Uint8Array): Promise + decrypt(data: Uint8Array, password: string | Uint8Array): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/errors.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/errors.ts new file mode 100644 index 000000000..2a8fc8a80 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/errors.ts @@ -0,0 +1,29 @@ +/** + * Signing a message failed + */ +export class SigningError extends Error { + constructor (message = 'An error occurred while signing a message') { + super(message) + this.name = 'SigningError' + } +} + +/** + * Verifying a message signature failed + */ +export class VerificationError extends Error { + constructor (message = 'An error occurred while verifying a message') { + super(message) + this.name = 'VerificationError' + } +} + +/** + * WebCrypto was not available in the current context + */ +export class WebCryptoMissingError extends Error { + constructor (message = 'Missing Web Crypto API') { + super(message) + this.name = 'WebCryptoMissingError' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/index.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/index.browser.ts new file mode 100644 index 000000000..fe59693dd --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/index.browser.ts @@ -0,0 +1,35 @@ +import webcrypto from '../webcrypto/index.js' +import lengths from './lengths.js' + +const hashTypes = { + SHA1: 'SHA-1', + SHA256: 'SHA-256', + SHA512: 'SHA-512' +} + +const sign = async (key: CryptoKey, data: Uint8Array): Promise => { + const buf = await webcrypto.get().subtle.sign({ name: 'HMAC' }, key, data) + return new Uint8Array(buf, 0, buf.byteLength) +} + +export async function create (hashType: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array): Promise<{ digest(data: Uint8Array): Promise, length: number }> { + const hash = hashTypes[hashType] + + const key = await webcrypto.get().subtle.importKey( + 'raw', + secret, + { + name: 'HMAC', + hash: { name: hash } + }, + false, + ['sign'] + ) + + return { + async digest (data: Uint8Array) { + return sign(key, data) + }, + length: lengths[hashType] + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/index.ts new file mode 100644 index 000000000..18f6ef499 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/index.ts @@ -0,0 +1,37 @@ +/** + * @packageDocumentation + * + * Exposes an interface to the Keyed-Hash Message Authentication Code (HMAC) as defined in U.S. Federal Information Processing Standards Publication 198. An HMAC is a cryptographic hash that uses a key to sign a message. The receiver verifies the hash by recomputing it using the same key. + * + * @example + * + * ```TypeScript + * import { create } from '@libp2p/hmac' + * + * const hash = 'SHA1' // 'SHA256' || 'SHA512' + * const hmac = await crypto.hmac.create(hash, uint8ArrayFromString('secret')) + * const sig = await hmac.digest(uint8ArrayFromString('hello world')) + * console.log(sig) + * ``` + */ + +import crypto from 'crypto' +import lengths from './lengths.js' + +export interface HMAC { + digest(data: Uint8Array): Promise + length: number +} + +export async function create (hash: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array): Promise { + const res = { + async digest (data: Uint8Array) { + const hmac = crypto.createHmac(hash.toLowerCase(), secret) + hmac.update(data) + return hmac.digest() + }, + length: lengths[hash] + } + + return res +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/lengths.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/lengths.ts new file mode 100644 index 000000000..925cc690f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/hmac/lengths.ts @@ -0,0 +1,5 @@ +export default { + SHA1: 20, + SHA256: 32, + SHA512: 64 +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/index.ts new file mode 100644 index 000000000..1a1df75cf --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/index.ts @@ -0,0 +1,19 @@ +/** + * @packageDocumentation + * + * The `libp2p-crypto` library depends on the [Web Crypto API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Crypto_API) in the browser. Web Crypto is available in all modern browsers, however browsers restrict its usage to [Secure Contexts](https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts). + * + * This means you will not be able to use some `@libp2p/crypto` functions in the browser when the page is served over HTTP.* + * + * To enable the Web Crypto API and allow `@libp2p/crypto` to work fully, please serve your page over HTTPS. + */ + +import * as hmac from './hmac/index.js' +import * as keys from './keys/index.js' +import pbkdf2 from './pbkdf2.js' +import randomBytes from './random-bytes.js' + +export { hmac } +export { keys } +export { randomBytes } +export { pbkdf2 } diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdh/index.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdh/index.browser.ts new file mode 100644 index 000000000..742bd19a7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdh/index.browser.ts @@ -0,0 +1,132 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { base64urlToBuffer } from '../../util.js' +import webcrypto from '../../webcrypto/index.js' +import type { Curve } from './index.js' +import type { ECDHKey, ECDHKeyPair, JWKEncodedPrivateKey, JWKEncodedPublicKey } from '../interface.js' + +const curveLengths = { + 'P-256': 32, + 'P-384': 48, + 'P-521': 66 +} + +const curveTypes = Object.keys(curveLengths) +const names = curveTypes.join(' / ') + +export async function generateEphemeralKeyPair (curve: Curve): Promise { + if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') { + throw new InvalidParametersError(`Unknown curve: ${curve}. Must be ${names}`) + } + + const pair = await webcrypto.get().subtle.generateKey( + { + name: 'ECDH', + namedCurve: curve + }, + true, + ['deriveBits'] + ) + + // forcePrivate is used for testing only + const genSharedKey = async (theirPub: Uint8Array, forcePrivate?: ECDHKeyPair): Promise => { + let privateKey + + if (forcePrivate != null) { + privateKey = await webcrypto.get().subtle.importKey( + 'jwk', + unmarshalPrivateKey(curve, forcePrivate), + { + name: 'ECDH', + namedCurve: curve + }, + false, + ['deriveBits'] + ) + } else { + privateKey = pair.privateKey + } + + const key = await webcrypto.get().subtle.importKey( + 'jwk', + unmarshalPublicKey(curve, theirPub), + { + name: 'ECDH', + namedCurve: curve + }, + false, + [] + ) + + const buffer = await webcrypto.get().subtle.deriveBits( + { + name: 'ECDH', + public: key + }, + privateKey, + curveLengths[curve] * 8 + ) + + return new Uint8Array(buffer, 0, buffer.byteLength) + } + + const publicKey = await webcrypto.get().subtle.exportKey('jwk', pair.publicKey) + + const ecdhKey: ECDHKey = { + key: marshalPublicKey(publicKey), + genSharedKey + } + + return ecdhKey +} + +// Marshal converts a jwk encoded ECDH public key into the +// form specified in section 4.3.6 of ANSI X9.62. (This is the format +// go-ipfs uses) +function marshalPublicKey (jwk: JsonWebKey): Uint8Array { + if (jwk.crv == null || jwk.x == null || jwk.y == null) { + throw new InvalidParametersError('JWK was missing components') + } + + if (jwk.crv !== 'P-256' && jwk.crv !== 'P-384' && jwk.crv !== 'P-521') { + throw new InvalidParametersError(`Unknown curve: ${jwk.crv}. Must be ${names}`) + } + + const byteLen = curveLengths[jwk.crv] + + return uint8ArrayConcat([ + Uint8Array.from([4]), // uncompressed point + base64urlToBuffer(jwk.x, byteLen), + base64urlToBuffer(jwk.y, byteLen) + ], 1 + byteLen * 2) +} + +/** + * Unmarshal converts a point, serialized by Marshal, into an jwk encoded key + */ +function unmarshalPublicKey (curve: Curve, key: Uint8Array): JWKEncodedPublicKey { + if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') { + throw new InvalidParametersError(`Unknown curve: ${curve}. Must be ${names}`) + } + + const byteLen = curveLengths[curve] + + if (!uint8ArrayEquals(key.subarray(0, 1), Uint8Array.from([4]))) { + throw new InvalidParametersError('Cannot unmarshal public key - invalid key format') + } + + return { + kty: 'EC', + crv: curve, + x: uint8ArrayToString(key.subarray(1, byteLen + 1), 'base64url'), + y: uint8ArrayToString(key.subarray(1 + byteLen), 'base64url'), + ext: true + } +} + +const unmarshalPrivateKey = (curve: Curve, key: ECDHKeyPair): JWKEncodedPrivateKey => ({ + ...unmarshalPublicKey(curve, key.public), + d: uint8ArrayToString(key.private, 'base64url') +}) diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdh/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdh/index.ts new file mode 100644 index 000000000..dd4d95766 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdh/index.ts @@ -0,0 +1,40 @@ +import crypto from 'crypto' +import { InvalidParametersError } from '@libp2p/interface' +import type { ECDHKey, ECDHKeyPair } from '../interface.js' + +export type Curve = 'P-256' | 'P-384' | 'P-521' + +const curves = { + 'P-256': 'prime256v1', + 'P-384': 'secp384r1', + 'P-521': 'secp521r1' +} + +const curveTypes = Object.keys(curves) +const names = curveTypes.join(' / ') + +/** + * Generates an ephemeral public key and returns a function that will compute the shared secret key. + * + * Focuses only on ECDH now, but can be made more general in the future. + */ +export async function generateEphemeralKeyPair (curve: Curve): Promise { + if (curve !== 'P-256' && curve !== 'P-384' && curve !== 'P-521') { + throw new InvalidParametersError(`Unknown curve: ${curve}. Must be ${names}`) + } + + const ecdh = crypto.createECDH(curves[curve]) + ecdh.generateKeys() + + return { + key: ecdh.getPublicKey() as Uint8Array, + + async genSharedKey (theirPub: Uint8Array, forcePrivate?: ECDHKeyPair): Promise { + if (forcePrivate != null) { + ecdh.setPrivateKey(forcePrivate.private) + } + + return ecdh.computeSecret(theirPub) + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/ecdsa.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/ecdsa.ts new file mode 100644 index 000000000..f15611a6e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/ecdsa.ts @@ -0,0 +1,91 @@ +import { base58btc } from 'multiformats/bases/base58' +import { CID } from 'multiformats/cid' +import { identity } from 'multiformats/hashes/identity' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { publicKeyToProtobuf } from '../index.js' +import { privateKeyToPKIMessage, publicKeyToPKIMessage } from './utils.js' +import { hashAndVerify, hashAndSign } from './index.js' +import type { ECDSAPublicKey as ECDSAPublicKeyInterface, ECDSAPrivateKey as ECDSAPrivateKeyInterface, AbortOptions } from '@libp2p/interface' +import type { Digest } from 'multiformats/hashes/digest' +import type { Uint8ArrayList } from 'uint8arraylist' + +export class ECDSAPublicKey implements ECDSAPublicKeyInterface { + public readonly type = 'ECDSA' + public readonly jwk: JsonWebKey + private _raw?: Uint8Array + + constructor (jwk: JsonWebKey) { + this.jwk = jwk + } + + get raw (): Uint8Array { + if (this._raw == null) { + this._raw = publicKeyToPKIMessage(this.jwk) + } + + return this._raw + } + + toMultihash (): Digest<0x0, number> { + return identity.digest(publicKeyToProtobuf(this)) + } + + toCID (): CID { + return CID.createV1(114, this.toMultihash()) + } + + toString (): string { + return base58btc.encode(this.toMultihash().bytes).substring(1) + } + + equals (key?: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + async verify (data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): Promise { + return hashAndVerify(this.jwk, sig, data, options) + } +} + +export class ECDSAPrivateKey implements ECDSAPrivateKeyInterface { + public readonly type = 'ECDSA' + public readonly jwk: JsonWebKey + public readonly publicKey: ECDSAPublicKey + private _raw?: Uint8Array + + constructor (jwk: JsonWebKey) { + this.jwk = jwk + this.publicKey = new ECDSAPublicKey({ + crv: jwk.crv, + ext: jwk.ext, + key_ops: ['verify'], + kty: 'EC', + x: jwk.x, + y: jwk.y + }) + } + + get raw (): Uint8Array { + if (this._raw == null) { + this._raw = privateKeyToPKIMessage(this.jwk) + } + + return this._raw + } + + equals (key?: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + async sign (message: Uint8Array | Uint8ArrayList, options?: AbortOptions): Promise { + return hashAndSign(this.jwk, message, options) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/index.ts new file mode 100644 index 000000000..e28138fde --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/index.ts @@ -0,0 +1,57 @@ +import type { JWKKeyPair } from '../interface.js' +import type { AbortOptions } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +export type Curve = 'P-256' | 'P-384' | 'P-521' + +export const ECDSA_P_256_OID = '1.2.840.10045.3.1.7' +export const ECDSA_P_384_OID = '1.3.132.0.34' +export const ECDSA_P_521_OID = '1.3.132.0.35' + +export async function generateECDSAKey (curve: Curve = 'P-256'): Promise { + const keyPair = await crypto.subtle.generateKey({ + name: 'ECDSA', + namedCurve: curve + }, true, ['sign', 'verify']) + + return { + publicKey: await crypto.subtle.exportKey('jwk', keyPair.publicKey), + privateKey: await crypto.subtle.exportKey('jwk', keyPair.privateKey) + } +} + +export async function hashAndSign (key: JsonWebKey, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): Promise { + const privateKey = await crypto.subtle.importKey('jwk', key, { + name: 'ECDSA', + namedCurve: key.crv ?? 'P-256' + }, false, ['sign']) + options?.signal?.throwIfAborted() + + const signature = await crypto.subtle.sign({ + name: 'ECDSA', + hash: { + name: 'SHA-256' + } + }, privateKey, msg.subarray()) + options?.signal?.throwIfAborted() + + return new Uint8Array(signature, 0, signature.byteLength) +} + +export async function hashAndVerify (key: JsonWebKey, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): Promise { + const publicKey = await crypto.subtle.importKey('jwk', key, { + name: 'ECDSA', + namedCurve: key.crv ?? 'P-256' + }, false, ['verify']) + options?.signal?.throwIfAborted() + + const result = await crypto.subtle.verify({ + name: 'ECDSA', + hash: { + name: 'SHA-256' + } + }, publicKey, sig, msg.subarray()) + options?.signal?.throwIfAborted() + + return result +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/utils.ts new file mode 100644 index 000000000..cdbcb075e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ecdsa/utils.ts @@ -0,0 +1,212 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { Uint8ArrayList } from 'uint8arraylist' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { decodeDer, encodeBitString, encodeInteger, encodeOctetString, encodeSequence } from '../rsa/der.js' +import { ECDSAPrivateKey as ECDSAPrivateKeyClass, ECDSAPublicKey as ECDSAPublicKeyClass } from './ecdsa.js' +import { generateECDSAKey } from './index.js' +import type { Curve } from '../ecdh/index.js' +import type { ECDSAPublicKey, ECDSAPrivateKey } from '@libp2p/interface' + +// 1.2.840.10045.3.1.7 prime256v1 (ANSI X9.62 named elliptic curve) +const OID_256 = Uint8Array.from([0x06, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07]) +// 1.3.132.0.34 secp384r1 (SECG (Certicom) named elliptic curve) +const OID_384 = Uint8Array.from([0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22]) +// 1.3.132.0.35 secp521r1 (SECG (Certicom) named elliptic curve) +const OID_521 = Uint8Array.from([0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23]) + +const P_256_KEY_JWK = { + ext: true, + kty: 'EC', + crv: 'P-256' +} + +const P_384_KEY_JWK = { + ext: true, + kty: 'EC', + crv: 'P-384' +} + +const P_521_KEY_JWK = { + ext: true, + kty: 'EC', + crv: 'P-521' +} + +const P_256_KEY_LENGTH = 32 +const P_384_KEY_LENGTH = 48 +const P_521_KEY_LENGTH = 66 + +export function unmarshalECDSAPrivateKey (bytes: Uint8Array): ECDSAPrivateKey { + const message = decodeDer(bytes) + + return pkiMessageToECDSAPrivateKey(message) +} + +export function pkiMessageToECDSAPrivateKey (message: any): ECDSAPrivateKey { + const privateKey = message[1] + const d = uint8ArrayToString(privateKey, 'base64url') + const coordinates: Uint8Array = message[2][1][0] + const offset = 1 + let x: string + let y: string + + if (privateKey.byteLength === P_256_KEY_LENGTH) { + x = uint8ArrayToString(coordinates.subarray(offset, offset + P_256_KEY_LENGTH), 'base64url') + y = uint8ArrayToString(coordinates.subarray(offset + P_256_KEY_LENGTH), 'base64url') + + return new ECDSAPrivateKeyClass({ + ...P_256_KEY_JWK, + key_ops: ['sign'], + d, + x, + y + }) + } + + if (privateKey.byteLength === P_384_KEY_LENGTH) { + x = uint8ArrayToString(coordinates.subarray(offset, offset + P_384_KEY_LENGTH), 'base64url') + y = uint8ArrayToString(coordinates.subarray(offset + P_384_KEY_LENGTH), 'base64url') + + return new ECDSAPrivateKeyClass({ + ...P_384_KEY_JWK, + key_ops: ['sign'], + d, + x, + y + }) + } + + if (privateKey.byteLength === P_521_KEY_LENGTH) { + x = uint8ArrayToString(coordinates.subarray(offset, offset + P_521_KEY_LENGTH), 'base64url') + y = uint8ArrayToString(coordinates.subarray(offset + P_521_KEY_LENGTH), 'base64url') + + return new ECDSAPrivateKeyClass({ + ...P_521_KEY_JWK, + key_ops: ['sign'], + d, + x, + y + }) + } + + throw new InvalidParametersError(`Private key length was wrong length, got ${privateKey.byteLength}, expected 32, 48 or 66`) +} + +export function unmarshalECDSAPublicKey (bytes: Uint8Array): ECDSAPublicKey { + const message = decodeDer(bytes) + + return pkiMessageToECDSAPublicKey(message) +} + +export function pkiMessageToECDSAPublicKey (message: any): ECDSAPublicKey { + const coordinates = message[1][1][0] + const offset = 1 + let x: string + let y: string + + if (coordinates.byteLength === ((P_256_KEY_LENGTH * 2) + 1)) { + x = uint8ArrayToString(coordinates.subarray(offset, offset + P_256_KEY_LENGTH), 'base64url') + y = uint8ArrayToString(coordinates.subarray(offset + P_256_KEY_LENGTH), 'base64url') + + return new ECDSAPublicKeyClass({ + ...P_256_KEY_JWK, + key_ops: ['verify'], + x, + y + }) + } + + if (coordinates.byteLength === ((P_384_KEY_LENGTH * 2) + 1)) { + x = uint8ArrayToString(coordinates.subarray(offset, offset + P_384_KEY_LENGTH), 'base64url') + y = uint8ArrayToString(coordinates.subarray(offset + P_384_KEY_LENGTH), 'base64url') + + return new ECDSAPublicKeyClass({ + ...P_384_KEY_JWK, + key_ops: ['verify'], + x, + y + }) + } + + if (coordinates.byteLength === ((P_521_KEY_LENGTH * 2) + 1)) { + x = uint8ArrayToString(coordinates.subarray(offset, offset + P_521_KEY_LENGTH), 'base64url') + y = uint8ArrayToString(coordinates.subarray(offset + P_521_KEY_LENGTH), 'base64url') + + return new ECDSAPublicKeyClass({ + ...P_521_KEY_JWK, + key_ops: ['verify'], + x, + y + }) + } + + throw new InvalidParametersError(`coordinates were wrong length, got ${coordinates.byteLength}, expected 65, 97 or 133`) +} + +export function privateKeyToPKIMessage (privateKey: JsonWebKey): Uint8Array { + return encodeSequence([ + encodeInteger(Uint8Array.from([1])), // header + encodeOctetString(uint8ArrayFromString(privateKey.d ?? '', 'base64url')), // body + encodeSequence([ // PKIProtection + getOID(privateKey.crv) + ], 0xA0), + encodeSequence([ // extraCerts + encodeBitString( + new Uint8ArrayList( + Uint8Array.from([0x04]), + uint8ArrayFromString(privateKey.x ?? '', 'base64url'), + uint8ArrayFromString(privateKey.y ?? '', 'base64url') + ) + ) + ], 0xA1) + ]).subarray() +} + +export function publicKeyToPKIMessage (publicKey: JsonWebKey): Uint8Array { + return encodeSequence([ + encodeInteger(Uint8Array.from([1])), // header + encodeSequence([ // PKIProtection + getOID(publicKey.crv) + ], 0xA0), + encodeSequence([ // extraCerts + encodeBitString( + new Uint8ArrayList( + Uint8Array.from([0x04]), + uint8ArrayFromString(publicKey.x ?? '', 'base64url'), + uint8ArrayFromString(publicKey.y ?? '', 'base64url') + ) + ) + ], 0xA1) + ]).subarray() +} + +function getOID (curve?: string): Uint8Array { + if (curve === 'P-256') { + return OID_256 + } + + if (curve === 'P-384') { + return OID_384 + } + + if (curve === 'P-521') { + return OID_521 + } + + throw new InvalidParametersError(`Invalid curve ${curve}`) +} + +export async function generateECDSAKeyPair (curve: Curve = 'P-256'): Promise { + const key = await generateECDSAKey(curve) + + return new ECDSAPrivateKeyClass(key.privateKey) +} + +export function ensureECDSAKey (key: Uint8Array, length: number): Uint8Array { + key = Uint8Array.from(key ?? []) + if (key.length !== length) { + throw new InvalidParametersError(`Key must be a Uint8Array of length ${length}, got ${key.length}`) + } + return key +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/ed25519.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/ed25519.ts new file mode 100644 index 000000000..06c1eb7d9 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/ed25519.ts @@ -0,0 +1,90 @@ +import { base58btc } from 'multiformats/bases/base58' +import { CID } from 'multiformats/cid' +import { identity } from 'multiformats/hashes/identity' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { isPromise } from '../../util.ts' +import { publicKeyToProtobuf } from '../index.js' +import { ensureEd25519Key } from './utils.js' +import * as crypto from './index.js' +import type { Ed25519PublicKey as Ed25519PublicKeyInterface, Ed25519PrivateKey as Ed25519PrivateKeyInterface, AbortOptions } from '@libp2p/interface' +import type { Digest } from 'multiformats/hashes/digest' +import type { Uint8ArrayList } from 'uint8arraylist' + +export class Ed25519PublicKey implements Ed25519PublicKeyInterface { + public readonly type = 'Ed25519' + public readonly raw: Uint8Array + + constructor (key: Uint8Array) { + this.raw = ensureEd25519Key(key, crypto.publicKeyLength) + } + + toMultihash (): Digest<0x0, number> { + return identity.digest(publicKeyToProtobuf(this)) + } + + toCID (): CID { + return CID.createV1(114, this.toMultihash()) + } + + toString (): string { + return base58btc.encode(this.toMultihash().bytes).substring(1) + } + + equals (key?: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + verify (data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): boolean | Promise { + options?.signal?.throwIfAborted() + const result = crypto.hashAndVerify(this.raw, sig, data) + + if (isPromise(result)) { + return result.then(res => { + options?.signal?.throwIfAborted() + return res + }) + } + + return result + } +} + +export class Ed25519PrivateKey implements Ed25519PrivateKeyInterface { + public readonly type = 'Ed25519' + public readonly raw: Uint8Array + public readonly publicKey: Ed25519PublicKey + + // key - 64 byte Uint8Array containing private key + // publicKey - 32 byte Uint8Array containing public key + constructor (key: Uint8Array, publicKey: Uint8Array) { + this.raw = ensureEd25519Key(key, crypto.privateKeyLength) + this.publicKey = new Ed25519PublicKey(publicKey) + } + + equals (key?: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + sign (message: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise { + options?.signal?.throwIfAborted() + const sig = crypto.hashAndSign(this.raw, message) + + if (isPromise(sig)) { + return sig.then(res => { + options?.signal?.throwIfAborted() + return res + }) + } + + options?.signal?.throwIfAborted() + return sig + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/index.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/index.browser.ts new file mode 100644 index 000000000..2114f629b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/index.browser.ts @@ -0,0 +1,132 @@ +import { ed25519 as ed } from '@noble/curves/ed25519' +import { toString as uint8arrayToString } from 'uint8arrays/to-string' +import crypto from '../../webcrypto/index.js' +import type { Uint8ArrayKeyPair } from '../interface.js' +import type { Uint8ArrayList } from 'uint8arraylist' + +const PUBLIC_KEY_BYTE_LENGTH = 32 +const PRIVATE_KEY_BYTE_LENGTH = 64 // private key is actually 32 bytes but for historical reasons we concat private and public keys +const KEYS_BYTE_LENGTH = 32 + +export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength } +export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength } + +// memoize support result to skip additional awaits every time we use an ed key +let ed25519Supported: boolean | undefined +const webCryptoEd25519SupportedPromise = (async () => { + try { + await crypto.get().subtle.generateKey({ name: 'Ed25519' }, true, ['sign', 'verify']) + return true + } catch { + return false + } +})() + +export function generateKey (): Uint8ArrayKeyPair { + // the actual private key (32 bytes) + const privateKeyRaw = ed.utils.randomPrivateKey() + const publicKey = ed.getPublicKey(privateKeyRaw) + + // concatenated the public key to the private key + const privateKey = concatKeys(privateKeyRaw, publicKey) + + return { + privateKey, + publicKey + } +} + +export function generateKeyFromSeed (seed: Uint8Array): Uint8ArrayKeyPair { + if (seed.length !== KEYS_BYTE_LENGTH) { + throw new TypeError('"seed" must be 32 bytes in length.') + } else if (!(seed instanceof Uint8Array)) { + throw new TypeError('"seed" must be a node.js Buffer, or Uint8Array.') + } + + // based on node forges algorithm, the seed is used directly as private key + const privateKeyRaw = seed + const publicKey = ed.getPublicKey(privateKeyRaw) + + const privateKey = concatKeys(privateKeyRaw, publicKey) + + return { + privateKey, + publicKey + } +} + +async function hashAndSignWebCrypto (privateKey: Uint8Array, msg: Uint8Array | Uint8ArrayList): Promise { + let privateKeyRaw: Uint8Array + if (privateKey.length === PRIVATE_KEY_BYTE_LENGTH) { + privateKeyRaw = privateKey.subarray(0, 32) + } else { + privateKeyRaw = privateKey + } + + const jwk: JsonWebKey = { + crv: 'Ed25519', + kty: 'OKP', + x: uint8arrayToString(privateKey.subarray(32), 'base64url'), + d: uint8arrayToString(privateKeyRaw, 'base64url'), + ext: true, + key_ops: ['sign'] + } + + const key = await crypto.get().subtle.importKey('jwk', jwk, { name: 'Ed25519' }, true, ['sign']) + const sig = await crypto.get().subtle.sign({ name: 'Ed25519' }, key, msg instanceof Uint8Array ? msg : msg.subarray()) + + return new Uint8Array(sig, 0, sig.byteLength) +} + +function hashAndSignNoble (privateKey: Uint8Array, msg: Uint8Array | Uint8ArrayList): Uint8Array { + const privateKeyRaw = privateKey.subarray(0, KEYS_BYTE_LENGTH) + + return ed.sign(msg instanceof Uint8Array ? msg : msg.subarray(), privateKeyRaw) +} + +export async function hashAndSign (privateKey: Uint8Array, msg: Uint8Array | Uint8ArrayList): Promise { + if (ed25519Supported == null) { + ed25519Supported = await webCryptoEd25519SupportedPromise + } + + if (ed25519Supported) { + return hashAndSignWebCrypto(privateKey, msg) + } + + return hashAndSignNoble(privateKey, msg) +} + +async function hashAndVerifyWebCrypto (publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList): Promise { + if (publicKey.buffer instanceof ArrayBuffer) { + const key = await crypto.get().subtle.importKey('raw', publicKey.buffer, { name: 'Ed25519' }, false, ['verify']) + const isValid = await crypto.get().subtle.verify({ name: 'Ed25519' }, key, sig, msg instanceof Uint8Array ? msg : msg.subarray()) + return isValid + } + + throw new TypeError('WebCrypto does not support SharedArrayBuffer for Ed25519 keys') +} + +function hashAndVerifyNoble (publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList): boolean { + return ed.verify(sig, msg instanceof Uint8Array ? msg : msg.subarray(), publicKey) +} + +export async function hashAndVerify (publicKey: Uint8Array, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList): Promise { + if (ed25519Supported == null) { + ed25519Supported = await webCryptoEd25519SupportedPromise + } + + if (ed25519Supported) { + return hashAndVerifyWebCrypto(publicKey, sig, msg) + } + + return hashAndVerifyNoble(publicKey, sig, msg) +} + +function concatKeys (privateKeyRaw: Uint8Array, publicKey: Uint8Array): Uint8Array { + const privateKey = new Uint8Array(PRIVATE_KEY_BYTE_LENGTH) + for (let i = 0; i < KEYS_BYTE_LENGTH; i++) { + privateKey[i] = privateKeyRaw[i] + privateKey[KEYS_BYTE_LENGTH + i] = publicKey[i] + } + return privateKey +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/index.ts new file mode 100644 index 000000000..d1ab445e9 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/index.ts @@ -0,0 +1,129 @@ +import crypto from 'crypto' +import { concat as uint8arrayConcat } from 'uint8arrays/concat' +import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' +import { toString as uint8arrayToString } from 'uint8arrays/to-string' +import type { Uint8ArrayKeyPair } from '../interface.js' +import type { Uint8ArrayList } from 'uint8arraylist' + +const keypair = crypto.generateKeyPairSync + +const PUBLIC_KEY_BYTE_LENGTH = 32 +const PRIVATE_KEY_BYTE_LENGTH = 64 // private key is actually 32 bytes but for historical reasons we concat private and public keys +const KEYS_BYTE_LENGTH = 32 +const SIGNATURE_BYTE_LENGTH = 64 + +export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength } +export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength } + +function derivePublicKey (privateKey: Uint8Array): Uint8Array { + const keyObject = crypto.createPrivateKey({ + format: 'jwk', + key: { + crv: 'Ed25519', + x: '', + d: uint8arrayToString(privateKey, 'base64url'), + kty: 'OKP' + } + }) + const jwk = keyObject.export({ + format: 'jwk' + }) + + if (jwk.x == null || jwk.x === '') { + throw new Error('Could not export JWK public key') + } + + return uint8arrayFromString(jwk.x, 'base64url') +} + +export function generateKey (): Uint8ArrayKeyPair { + const key = keypair('ed25519', { + publicKeyEncoding: { type: 'spki', format: 'jwk' }, + privateKeyEncoding: { type: 'pkcs8', format: 'jwk' } + }) + + // @ts-expect-error node types are missing jwk as a format + const privateKeyRaw = uint8arrayFromString(key.privateKey.d, 'base64url') + // @ts-expect-error node types are missing jwk as a format + const publicKeyRaw = uint8arrayFromString(key.publicKey.x, 'base64url') + + return { + privateKey: uint8arrayConcat([privateKeyRaw, publicKeyRaw], privateKeyRaw.byteLength + publicKeyRaw.byteLength), + publicKey: publicKeyRaw + } +} + +/** + * Generate keypair from a 32 byte uint8array + */ +export function generateKeyFromSeed (seed: Uint8Array): Uint8ArrayKeyPair { + if (seed.length !== KEYS_BYTE_LENGTH) { + throw new TypeError('"seed" must be 32 bytes in length.') + } else if (!(seed instanceof Uint8Array)) { + throw new TypeError('"seed" must be a node.js Buffer, or Uint8Array.') + } + + // based on node forges algorithm, the seed is used directly as private key + const publicKeyRaw = derivePublicKey(seed) + + return { + privateKey: uint8arrayConcat([seed, publicKeyRaw], seed.byteLength + publicKeyRaw.byteLength), + publicKey: publicKeyRaw + } +} + +export function hashAndSign (key: Uint8Array, msg: Uint8Array | Uint8ArrayList): Uint8Array { + if (!(key instanceof Uint8Array)) { + throw new TypeError('"key" must be a node.js Buffer, or Uint8Array.') + } + + let privateKey: Uint8Array + let publicKey: Uint8Array + + if (key.byteLength === PRIVATE_KEY_BYTE_LENGTH) { + privateKey = key.subarray(0, 32) + publicKey = key.subarray(32) + } else if (key.byteLength === KEYS_BYTE_LENGTH) { + privateKey = key.subarray(0, 32) + publicKey = derivePublicKey(privateKey) + } else { + throw new TypeError('"key" must be 64 or 32 bytes in length.') + } + + const obj = crypto.createPrivateKey({ + format: 'jwk', + key: { + crv: 'Ed25519', + d: uint8arrayToString(privateKey, 'base64url'), + x: uint8arrayToString(publicKey, 'base64url'), + kty: 'OKP' + } + }) + + return crypto.sign(null, msg instanceof Uint8Array ? msg : msg.subarray(), obj) +} + +export function hashAndVerify (key: Uint8Array, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList): boolean { + if (key.byteLength !== PUBLIC_KEY_BYTE_LENGTH) { + throw new TypeError('"key" must be 32 bytes in length.') + } else if (!(key instanceof Uint8Array)) { + throw new TypeError('"key" must be a node.js Buffer, or Uint8Array.') + } + + if (sig.byteLength !== SIGNATURE_BYTE_LENGTH) { + throw new TypeError('"sig" must be 64 bytes in length.') + } else if (!(sig instanceof Uint8Array)) { + throw new TypeError('"sig" must be a node.js Buffer, or Uint8Array.') + } + + const obj = crypto.createPublicKey({ + format: 'jwk', + key: { + crv: 'Ed25519', + x: uint8arrayToString(key, 'base64url'), + kty: 'OKP' + } + }) + + return crypto.verify(null, msg instanceof Uint8Array ? msg : msg.subarray(), obj, sig) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/utils.ts new file mode 100644 index 000000000..0268a4567 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ed25519/utils.ts @@ -0,0 +1,42 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { Ed25519PublicKey as Ed25519PublicKeyClass, Ed25519PrivateKey as Ed25519PrivateKeyClass } from './ed25519.js' +import * as crypto from './index.js' +import type { Ed25519PublicKey, Ed25519PrivateKey } from '@libp2p/interface' + +export function unmarshalEd25519PrivateKey (bytes: Uint8Array): Ed25519PrivateKey { + // Try the old, redundant public key version + if (bytes.length > crypto.privateKeyLength) { + bytes = ensureEd25519Key(bytes, crypto.privateKeyLength + crypto.publicKeyLength) + const privateKeyBytes = bytes.subarray(0, crypto.privateKeyLength) + const publicKeyBytes = bytes.subarray(crypto.privateKeyLength, bytes.length) + return new Ed25519PrivateKeyClass(privateKeyBytes, publicKeyBytes) + } + + bytes = ensureEd25519Key(bytes, crypto.privateKeyLength) + const privateKeyBytes = bytes.subarray(0, crypto.privateKeyLength) + const publicKeyBytes = bytes.subarray(crypto.publicKeyLength) + return new Ed25519PrivateKeyClass(privateKeyBytes, publicKeyBytes) +} + +export function unmarshalEd25519PublicKey (bytes: Uint8Array): Ed25519PublicKey { + bytes = ensureEd25519Key(bytes, crypto.publicKeyLength) + return new Ed25519PublicKeyClass(bytes) +} + +export async function generateEd25519KeyPair (): Promise { + const { privateKey, publicKey } = crypto.generateKey() + return new Ed25519PrivateKeyClass(privateKey, publicKey) +} + +export async function generateEd25519KeyPairFromSeed (seed: Uint8Array): Promise { + const { privateKey, publicKey } = crypto.generateKeyFromSeed(seed) + return new Ed25519PrivateKeyClass(privateKey, publicKey) +} + +export function ensureEd25519Key (key: Uint8Array, length: number): Uint8Array { + key = Uint8Array.from(key ?? []) + if (key.length !== length) { + throw new InvalidParametersError(`Key must be a Uint8Array of length ${length}, got ${key.length}`) + } + return key +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ephemeral-keys.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ephemeral-keys.ts new file mode 100644 index 000000000..dbfa4eccb --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/ephemeral-keys.ts @@ -0,0 +1,9 @@ +import { generateEphemeralKeyPair } from './ecdh/index.js' + +/** + * Generates an ephemeral public key and returns a function that will compute + * the shared secret key. + * + * Focuses only on ECDH now, but can be made more general in the future. + */ +export default generateEphemeralKeyPair diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/index.ts new file mode 100644 index 000000000..af54de387 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/index.ts @@ -0,0 +1,292 @@ +/** + * @packageDocumentation + * + * ## Supported Key Types + * + * Currently the `'RSA'`, `'ed25519'`, and `secp256k1` types are supported, although ed25519 and secp256k1 keys support only signing and verification of messages. + * + * For encryption / decryption support, RSA keys should be used. + */ + +import { InvalidParametersError, UnsupportedKeyTypeError } from '@libp2p/interface' +import { ECDSAPrivateKey as ECDSAPrivateKeyClass } from './ecdsa/ecdsa.js' +import { ECDSA_P_256_OID, ECDSA_P_384_OID, ECDSA_P_521_OID } from './ecdsa/index.js' +import { generateECDSAKeyPair, pkiMessageToECDSAPrivateKey, pkiMessageToECDSAPublicKey, unmarshalECDSAPrivateKey, unmarshalECDSAPublicKey } from './ecdsa/utils.js' +import { privateKeyLength as ed25519PrivateKeyLength, publicKeyLength as ed25519PublicKeyLength } from './ed25519/index.js' +import { generateEd25519KeyPair, generateEd25519KeyPairFromSeed, unmarshalEd25519PrivateKey, unmarshalEd25519PublicKey } from './ed25519/utils.js' +import * as pb from './keys.js' +import { decodeDer } from './rsa/der.js' +import { RSAES_PKCS1_V1_5_OID } from './rsa/index.js' +import { pkcs1ToRSAPrivateKey, pkixToRSAPublicKey, generateRSAKeyPair, pkcs1MessageToRSAPrivateKey, pkixMessageToRSAPublicKey, jwkToRSAPrivateKey } from './rsa/utils.js' +import { privateKeyLength as secp256k1PrivateKeyLength, publicKeyLength as secp256k1PublicKeyLength } from './secp256k1/index.js' +import { generateSecp256k1KeyPair, unmarshalSecp256k1PrivateKey, unmarshalSecp256k1PublicKey } from './secp256k1/utils.js' +import type { Curve } from './ecdsa/index.js' +import type { PrivateKey, PublicKey, KeyType, RSAPrivateKey, Secp256k1PrivateKey, Ed25519PrivateKey, Secp256k1PublicKey, Ed25519PublicKey, ECDSAPrivateKey, ECDSAPublicKey } from '@libp2p/interface' +import type { MultihashDigest } from 'multiformats' +import type { Digest } from 'multiformats/hashes/digest' + +export { generateEphemeralKeyPair } from './ecdh/index.js' +export type { Curve } from './ecdh/index.js' +export type { ECDHKey, EnhancedKey, EnhancedKeyPair, ECDHKeyPair } from './interface.js' +export { keyStretcher } from './key-stretcher.js' + +/** + * Generates a keypair of the given type and bitsize + */ +export async function generateKeyPair (type: 'Ed25519'): Promise +export async function generateKeyPair (type: 'secp256k1'): Promise +export async function generateKeyPair (type: 'ECDSA', curve?: Curve): Promise +export async function generateKeyPair (type: 'RSA', bits?: number): Promise +export async function generateKeyPair (type: KeyType, bits?: number): Promise +export async function generateKeyPair (type: KeyType, bits?: number | string): Promise { + if (type === 'Ed25519') { + return generateEd25519KeyPair() + } + + if (type === 'secp256k1') { + return generateSecp256k1KeyPair() + } + + if (type === 'RSA') { + return generateRSAKeyPair(toBits(bits)) + } + + if (type === 'ECDSA') { + return generateECDSAKeyPair(toCurve(bits)) + } + + throw new UnsupportedKeyTypeError() +} + +/** + * Generates a keypair of the given type from the passed seed. Currently only + * supports Ed25519 keys. + * + * Seed is a 32 byte uint8array + */ +export async function generateKeyPairFromSeed (type: 'Ed25519', seed: Uint8Array): Promise +export async function generateKeyPairFromSeed (type: T, seed: Uint8Array, bits?: number): Promise +export async function generateKeyPairFromSeed (type: string, seed: Uint8Array): Promise { + if (type !== 'Ed25519') { + throw new UnsupportedKeyTypeError('Seed key derivation only supported for Ed25519 keys') + } + + return generateEd25519KeyPairFromSeed(seed) +} + +/** + * Converts a protobuf serialized public key into its representative object. + * + * For RSA public keys optionally pass the multihash digest of the public key if + * it is known. If the digest is omitted it will be calculated which can be + * expensive. + * + * For other key types the digest option is ignored. + */ +export function publicKeyFromProtobuf (buf: Uint8Array, digest?: Digest<18, number>): PublicKey { + const { Type, Data } = pb.PublicKey.decode(buf) + const data = Data ?? new Uint8Array() + + switch (Type) { + case pb.KeyType.RSA: + return pkixToRSAPublicKey(data, digest) + case pb.KeyType.Ed25519: + return unmarshalEd25519PublicKey(data) + case pb.KeyType.secp256k1: + return unmarshalSecp256k1PublicKey(data) + case pb.KeyType.ECDSA: + return unmarshalECDSAPublicKey(data) + default: + throw new UnsupportedKeyTypeError() + } +} + +/** + * Creates a public key from the raw key bytes + */ +export function publicKeyFromRaw (buf: Uint8Array): PublicKey { + if (buf.byteLength === ed25519PublicKeyLength) { + return unmarshalEd25519PublicKey(buf) + } else if (buf.byteLength === secp256k1PublicKeyLength) { + return unmarshalSecp256k1PublicKey(buf) + } + + const message = decodeDer(buf) + const ecdsaOid = message[1]?.[0] + + if (ecdsaOid === ECDSA_P_256_OID || ecdsaOid === ECDSA_P_384_OID || ecdsaOid === ECDSA_P_521_OID) { + return pkiMessageToECDSAPublicKey(message) + } + + if (message[0]?.[0] === RSAES_PKCS1_V1_5_OID) { + return pkixMessageToRSAPublicKey(message, buf) + } + + throw new InvalidParametersError('Could not extract public key from raw bytes') +} + +/** + * Creates a public key from an identity multihash which contains a protobuf + * encoded Ed25519 or secp256k1 public key. + * + * RSA keys are not supported as in practice we they are not stored in identity + * multihash since the hash would be very large. + */ +export function publicKeyFromMultihash (digest: MultihashDigest<0x0>): Ed25519PublicKey | Secp256k1PublicKey | ECDSAPublicKey { + const { Type, Data } = pb.PublicKey.decode(digest.digest) + const data = Data ?? new Uint8Array() + + switch (Type) { + case pb.KeyType.Ed25519: + return unmarshalEd25519PublicKey(data) + case pb.KeyType.secp256k1: + return unmarshalSecp256k1PublicKey(data) + case pb.KeyType.ECDSA: + return unmarshalECDSAPublicKey(data) + default: + throw new UnsupportedKeyTypeError() + } +} + +/** + * Converts a public key object into a protobuf serialized public key + */ +export function publicKeyToProtobuf (key: PublicKey): Uint8Array { + return pb.PublicKey.encode({ + Type: pb.KeyType[key.type], + Data: key.raw + }) +} + +/** + * Converts a protobuf serialized private key into its representative object + */ +export function privateKeyFromProtobuf (buf: Uint8Array): Ed25519PrivateKey | Secp256k1PrivateKey | RSAPrivateKey | ECDSAPrivateKey { + const decoded = pb.PrivateKey.decode(buf) + const data = decoded.Data ?? new Uint8Array() + + switch (decoded.Type) { + case pb.KeyType.RSA: + return pkcs1ToRSAPrivateKey(data) + case pb.KeyType.Ed25519: + return unmarshalEd25519PrivateKey(data) + case pb.KeyType.secp256k1: + return unmarshalSecp256k1PrivateKey(data) + case pb.KeyType.ECDSA: + return unmarshalECDSAPrivateKey(data) + default: + throw new UnsupportedKeyTypeError() + } +} + +/** + * Creates a private key from the raw key bytes. For Ed25519 keys this requires + * the public key to be appended to the private key otherwise we can't + * differentiate between Ed25519 and secp256k1 keys as they are the same length. + */ +export function privateKeyFromRaw (buf: Uint8Array): PrivateKey { + if (buf.byteLength === ed25519PrivateKeyLength) { + return unmarshalEd25519PrivateKey(buf) + } else if (buf.byteLength === secp256k1PrivateKeyLength) { + return unmarshalSecp256k1PrivateKey(buf) + } + + const message = decodeDer(buf) + const ecdsaOid = message[2]?.[0] + + if (ecdsaOid === ECDSA_P_256_OID || ecdsaOid === ECDSA_P_384_OID || ecdsaOid === ECDSA_P_521_OID) { + return pkiMessageToECDSAPrivateKey(message) + } + + if (message.length > 8) { + return pkcs1MessageToRSAPrivateKey(message) + } + + throw new InvalidParametersError('Could not extract private key from raw bytes') +} + +/** + * Converts a private key object into a protobuf serialized private key + */ +export function privateKeyToProtobuf (key: PrivateKey): Uint8Array { + return pb.PrivateKey.encode({ + Type: pb.KeyType[key.type], + Data: key.raw + }) +} + +function toBits (bits: any): number { + if (bits == null) { + return 2048 + } + + return parseInt(bits, 10) +} + +function toCurve (curve: any): Curve { + if (curve === 'P-256' || curve == null) { + return 'P-256' + } + + if (curve === 'P-384') { + return 'P-384' + } + + if (curve === 'P-521') { + return 'P-521' + } + + throw new InvalidParametersError('Unsupported curve, should be P-256, P-384 or P-521') +} + +/** + * Convert a libp2p RSA or ECDSA private key to a WebCrypto CryptoKeyPair + */ +export async function privateKeyToCryptoKeyPair (privateKey: PrivateKey): Promise { + if (privateKey.type === 'RSA') { + return { + privateKey: await crypto.subtle.importKey('jwk', privateKey.jwk, { + name: 'RSASSA-PKCS1-v1_5', + hash: { name: 'SHA-256' } + }, true, ['sign']), + publicKey: await crypto.subtle.importKey('jwk', privateKey.publicKey.jwk, { + name: 'RSASSA-PKCS1-v1_5', + hash: { name: 'SHA-256' } + }, true, ['verify']) + } + } + + if (privateKey.type === 'ECDSA') { + return { + privateKey: await crypto.subtle.importKey('jwk', privateKey.jwk, { + name: 'ECDSA', + namedCurve: privateKey.jwk.crv ?? 'P-256' + }, true, ['sign']), + publicKey: await crypto.subtle.importKey('jwk', privateKey.publicKey.jwk, { + name: 'ECDSA', + namedCurve: privateKey.publicKey.jwk.crv ?? 'P-256' + }, true, ['verify']) + } + } + + throw new InvalidParametersError('Only RSA and ECDSA keys are supported') +} + +/** + * Convert a RSA or ECDSA WebCrypto CryptoKeyPair to a libp2p private key + */ +export async function privateKeyFromCryptoKeyPair (keyPair: CryptoKeyPair): Promise { + if (keyPair.privateKey.algorithm.name === 'RSASSA-PKCS1-v1_5') { + const jwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey) + + return jwkToRSAPrivateKey(jwk) + } + + if (keyPair.privateKey.algorithm.name === 'ECDSA') { + const jwk = await crypto.subtle.exportKey('jwk', keyPair.privateKey) + + return new ECDSAPrivateKeyClass(jwk) + } + + throw new InvalidParametersError('Only RSA and ECDSA keys are supported') +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/interface.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/interface.ts new file mode 100644 index 000000000..2cbfd5a12 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/interface.ts @@ -0,0 +1,34 @@ +export interface JWKKeyPair { + privateKey: JsonWebKey + publicKey: JsonWebKey +} + +export interface Uint8ArrayKeyPair { + privateKey: Uint8Array + publicKey: Uint8Array +} + +export interface ECDHKeyPair { + private: Uint8Array + public: Uint8Array +} + +export interface ECDHKey { + key: Uint8Array + genSharedKey(theirPub: Uint8Array, forcePrivate?: ECDHKeyPair): Promise +} + +export interface JWKEncodedPublicKey { kty: string, crv: 'P-256' | 'P-384' | 'P-521', x: string, y: string, ext: boolean } + +export interface JWKEncodedPrivateKey extends JWKEncodedPublicKey { d: string } + +export interface EnhancedKey { + iv: Uint8Array + cipherKey: Uint8Array + macKey: Uint8Array +} + +export interface EnhancedKeyPair { + k1: EnhancedKey + k2: EnhancedKey +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/key-stretcher.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/key-stretcher.ts new file mode 100644 index 000000000..29258feca --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/key-stretcher.ts @@ -0,0 +1,85 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import * as hmac from '../hmac/index.js' +import type { EnhancedKey, EnhancedKeyPair } from './interface.js' + +interface Cipher { + ivSize: number + keySize: number +} + +const cipherMap: Record = { + 'AES-128': { + ivSize: 16, + keySize: 16 + }, + 'AES-256': { + ivSize: 16, + keySize: 32 + }, + Blowfish: { + ivSize: 8, + keySize: 32 + } +} + +/** + * Generates a set of keys for each party by stretching the shared key. + * (myIV, theirIV, myCipherKey, theirCipherKey, myMACKey, theirMACKey) + */ +export async function keyStretcher (cipherType: 'AES-128' | 'AES-256' | 'Blowfish', hash: 'SHA1' | 'SHA256' | 'SHA512', secret: Uint8Array): Promise { + if (cipherType !== 'AES-128' && cipherType !== 'AES-256' && cipherType !== 'Blowfish') { + throw new InvalidParametersError('Cipher type was missing or unsupported') + } + + if (hash !== 'SHA1' && hash !== 'SHA256' && hash !== 'SHA512') { + throw new InvalidParametersError('Hash type was missing or unsupported') + } + + if (secret == null || !(secret instanceof Uint8Array)) { + throw new InvalidParametersError('Secret was missing or an incorrect type') + } + + const cipher = cipherMap[cipherType] + const cipherKeySize = cipher.keySize + const ivSize = cipher.ivSize + const hmacKeySize = 20 + const seed = uint8ArrayFromString('key expansion') + const resultLength = 2 * (ivSize + cipherKeySize + hmacKeySize) + + const m = await hmac.create(hash, secret) + let a = await m.digest(seed) + + const result = [] + let j = 0 + + while (j < resultLength) { + const b = await m.digest(uint8ArrayConcat([a, seed])) + let todo = b.length + + if (j + todo > resultLength) { + todo = resultLength - j + } + + result.push(b) + j += todo + a = await m.digest(a) + } + + const half = resultLength / 2 + const resultBuffer = uint8ArrayConcat(result) + const r1 = resultBuffer.subarray(0, half) + const r2 = resultBuffer.subarray(half, resultLength) + + const createKey = (res: Uint8Array): EnhancedKey => ({ + iv: res.subarray(0, ivSize), + cipherKey: res.subarray(ivSize, ivSize + cipherKeySize), + macKey: res.subarray(ivSize + cipherKeySize) + }) + + return { + k1: createKey(r1), + k2: createKey(r2) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/keys.proto b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/keys.proto new file mode 100644 index 000000000..d3ff6cf26 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/keys.proto @@ -0,0 +1,34 @@ +syntax = "proto3"; + +enum KeyType { + RSA = 0; + Ed25519 = 1; + secp256k1 = 2; + ECDSA = 3; +} +message PublicKey { + // the proto2 version of this field is "required" which means it will have + // no default value. the default for proto3 is "singluar" which omits the + // value on the wire if it's the default so for proto3 we make it "optional" + // to ensure a value is always written on to the wire + optional KeyType Type = 1; + + // the proto2 version of this field is "required" which means it will have + // no default value. the default for proto3 is "singluar" which omits the + // value on the wire if it's the default so for proto3 we make it "optional" + // to ensure a value is always written on to the wire + optional bytes Data = 2; +} +message PrivateKey { + // the proto2 version of this field is "required" which means it will have + // no default value. the default for proto3 is "singluar" which omits the + // value on the wire if it's the default so for proto3 we make it "optional" + // to ensure a value is always written on to the wire + optional KeyType Type = 1; + + // the proto2 version of this field is "required" which means it will have + // no default value. the default for proto3 is "singluar" which omits the + // value on the wire if it's the default so for proto3 we make it "optional" + // to ensure a value is always written on to the wire + optional bytes Data = 2; +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/keys.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/keys.ts new file mode 100644 index 000000000..afd2ac719 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/keys.ts @@ -0,0 +1,158 @@ +import { decodeMessage, encodeMessage, enumeration, message } from 'protons-runtime' +import type { Codec, DecodeOptions } from 'protons-runtime' +import type { Uint8ArrayList } from 'uint8arraylist' + +export enum KeyType { + RSA = 'RSA', + Ed25519 = 'Ed25519', + secp256k1 = 'secp256k1', + ECDSA = 'ECDSA' +} + +enum __KeyTypeValues { + RSA = 0, + Ed25519 = 1, + secp256k1 = 2, + ECDSA = 3 +} + +export namespace KeyType { + export const codec = (): Codec => { + return enumeration(__KeyTypeValues) + } +} +export interface PublicKey { + Type?: KeyType + Data?: Uint8Array +} + +export namespace PublicKey { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if (obj.Type != null) { + w.uint32(8) + KeyType.codec().encode(obj.Type, w) + } + + if (obj.Data != null) { + w.uint32(18) + w.bytes(obj.Data) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = {} + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.Type = KeyType.codec().decode(reader) + break + } + case 2: { + obj.Data = reader.bytes() + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }) + } + + return _codec + } + + export const encode = (obj: Partial): Uint8Array => { + return encodeMessage(obj, PublicKey.codec()) + } + + export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PublicKey => { + return decodeMessage(buf, PublicKey.codec(), opts) + } +} + +export interface PrivateKey { + Type?: KeyType + Data?: Uint8Array +} + +export namespace PrivateKey { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if (obj.Type != null) { + w.uint32(8) + KeyType.codec().encode(obj.Type, w) + } + + if (obj.Data != null) { + w.uint32(18) + w.bytes(obj.Data) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = {} + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.Type = KeyType.codec().decode(reader) + break + } + case 2: { + obj.Data = reader.bytes() + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }) + } + + return _codec + } + + export const encode = (obj: Partial): Uint8Array => { + return encodeMessage(obj, PrivateKey.codec()) + } + + export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PrivateKey => { + return decodeMessage(buf, PrivateKey.codec(), opts) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/der.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/der.ts new file mode 100644 index 000000000..0efe3bcd2 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/der.ts @@ -0,0 +1,269 @@ +import { Uint8ArrayList } from 'uint8arraylist' + +interface Context { + offset: number +} + +const TAG_MASK = parseInt('11111', 2) +const LONG_LENGTH_MASK = parseInt('10000000', 2) +const LONG_LENGTH_BYTES_MASK = parseInt('01111111', 2) + +interface Decoder { + (buf: Uint8Array, context: Context): any +} + +const decoders: Record = { + 0x0: readSequence, + 0x1: readSequence, + 0x2: readInteger, + 0x3: readBitString, + 0x4: readOctetString, + 0x5: readNull, + 0x6: readObjectIdentifier, + 0x10: readSequence, + 0x16: readSequence, + 0x30: readSequence +} + +export function decodeDer (buf: Uint8Array, context: Context = { offset: 0 }): any { + const tag = buf[context.offset] & TAG_MASK + context.offset++ + + if (decoders[tag] != null) { + return decoders[tag](buf, context) + } + + throw new Error('No decoder for tag ' + tag) +} + +function readLength (buf: Uint8Array, context: Context): number { + let length = 0 + + if ((buf[context.offset] & LONG_LENGTH_MASK) === LONG_LENGTH_MASK) { + // long length + const count = buf[context.offset] & LONG_LENGTH_BYTES_MASK + let str = '0x' + context.offset++ + + for (let i = 0; i < count; i++, context.offset++) { + str += buf[context.offset].toString(16).padStart(2, '0') + } + + length = parseInt(str, 16) + } else { + length = buf[context.offset] + context.offset++ + } + + return length +} + +function readSequence (buf: Uint8Array, context: Context): any[] { + readLength(buf, context) + const entries: any[] = [] + + while (true) { + if (context.offset >= buf.byteLength) { + break + } + + const result = decodeDer(buf, context) + + if (result === null) { + break + } + + entries.push(result) + } + + return entries +} + +function readInteger (buf: Uint8Array, context: Context): Uint8Array { + const length = readLength(buf, context) + const start = context.offset + const end = context.offset + length + + const vals: number[] = [] + + for (let i = start; i < end; i++) { + if (i === start && buf[i] === 0) { + continue + } + + vals.push(buf[i]) + } + + context.offset += length + + return Uint8Array.from(vals) +} + +function readObjectIdentifier (buf: Uint8Array, context: Context): string { + const count = readLength(buf, context) + const finalOffset = context.offset + count + + const byte = buf[context.offset] + context.offset++ + + let val1 = 0 + let val2 = 0 + + if (byte < 40) { + val1 = 0 + val2 = byte + } else if (byte < 80) { + val1 = 1 + val2 = byte - 40 + } else { + val1 = 2 + val2 = byte - 80 + } + + let oid = `${val1}.${val2}` + let num: number[] = [] + + while (context.offset < finalOffset) { + const byte = buf[context.offset] + context.offset++ + + // remove msb + num.push(byte & 0b01111111) + + if (byte < 128) { + num.reverse() + + // reached the end of the encoding + let val = 0 + + for (let i = 0; i < num.length; i++) { + val += num[i] << (i * 7) + } + + oid += `.${val}` + num = [] + } + } + + return oid +} + +function readNull (buf: Uint8Array, context: Context): null { + context.offset++ + + return null +} + +function readBitString (buf: Uint8Array, context: Context): any { + const length = readLength(buf, context) + const unusedBits = buf[context.offset] + context.offset++ + const bytes = buf.subarray(context.offset, context.offset + length - 1) + context.offset += length + + if (unusedBits !== 0) { + // need to shift all bytes along by this many bits + throw new Error('Unused bits in bit string is unimplemented') + } + + return bytes +} + +function readOctetString (buf: Uint8Array, context: Context): any { + const length = readLength(buf, context) + const bytes = buf.subarray(context.offset, context.offset + length) + context.offset += length + + return bytes +} + +function encodeNumber (value: number): Uint8ArrayList { + let number = value.toString(16) + + if (number.length % 2 === 1) { + number = '0' + number + } + + const array = new Uint8ArrayList() + + for (let i = 0; i < number.length; i += 2) { + array.append(Uint8Array.from([parseInt(`${number[i]}${number[i + 1]}`, 16)])) + } + + return array +} + +function encodeLength (bytes: { byteLength: number }): Uint8Array | Uint8ArrayList { + if (bytes.byteLength < 128) { + return Uint8Array.from([bytes.byteLength]) + } + + // long length + const length = encodeNumber(bytes.byteLength) + + return new Uint8ArrayList( + Uint8Array.from([ + length.byteLength | LONG_LENGTH_MASK + ]), + length + ) +} + +export function encodeInteger (value: Uint8Array | Uint8ArrayList): Uint8ArrayList { + const contents = new Uint8ArrayList() + + const mask = 0b10000000 + const positive = (value.subarray()[0] & mask) === mask + + if (positive) { + contents.append(Uint8Array.from([0])) + } + + contents.append(value) + + return new Uint8ArrayList( + Uint8Array.from([0x02]), + encodeLength(contents), + contents + ) +} + +export function encodeBitString (value: Uint8Array | Uint8ArrayList): Uint8ArrayList { + // unused bits is always 0 with full-byte-only values + const unusedBits = Uint8Array.from([0]) + + const contents = new Uint8ArrayList( + unusedBits, + value + ) + + return new Uint8ArrayList( + Uint8Array.from([0x03]), + encodeLength(contents), + contents + ) +} + +export function encodeOctetString (value: Uint8Array | Uint8ArrayList): Uint8ArrayList { + return new Uint8ArrayList( + Uint8Array.from([0x04]), + encodeLength(value), + value + ) +} + +export function encodeSequence (values: Array, tag = 0x30): Uint8ArrayList { + const output = new Uint8ArrayList() + + for (const buf of values) { + output.append( + buf + ) + } + + return new Uint8ArrayList( + Uint8Array.from([tag]), + encodeLength(output), + output + ) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/index.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/index.browser.ts new file mode 100644 index 000000000..13745ab22 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/index.browser.ts @@ -0,0 +1,105 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import randomBytes from '../../random-bytes.js' +import webcrypto from '../../webcrypto/index.js' +import * as utils from './utils.js' +import type { JWKKeyPair } from '../interface.js' +import type { AbortOptions } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +export const RSAES_PKCS1_V1_5_OID = '1.2.840.113549.1.1.1' +export { utils } + +export async function generateRSAKey (bits: number, options?: AbortOptions): Promise { + const pair = await webcrypto.get().subtle.generateKey( + { + name: 'RSASSA-PKCS1-v1_5', + modulusLength: bits, + publicExponent: new Uint8Array([0x01, 0x00, 0x01]), + hash: { name: 'SHA-256' } + }, + true, + ['sign', 'verify'] + ) + options?.signal?.throwIfAborted() + + const keys = await exportKey(pair, options) + + return { + privateKey: keys[0], + publicKey: keys[1] + } +} + +export { randomBytes as getRandomValues } + +export async function hashAndSign (key: JsonWebKey, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): Promise { + const privateKey = await webcrypto.get().subtle.importKey( + 'jwk', + key, + { + name: 'RSASSA-PKCS1-v1_5', + hash: { name: 'SHA-256' } + }, + false, + ['sign'] + ) + options?.signal?.throwIfAborted() + + const sig = await webcrypto.get().subtle.sign( + { name: 'RSASSA-PKCS1-v1_5' }, + privateKey, + msg instanceof Uint8Array ? msg : msg.subarray() + ) + options?.signal?.throwIfAborted() + + return new Uint8Array(sig, 0, sig.byteLength) +} + +export async function hashAndVerify (key: JsonWebKey, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): Promise { + const publicKey = await webcrypto.get().subtle.importKey( + 'jwk', + key, + { + name: 'RSASSA-PKCS1-v1_5', + hash: { name: 'SHA-256' } + }, + false, + ['verify'] + ) + options?.signal?.throwIfAborted() + + const result = await webcrypto.get().subtle.verify( + { name: 'RSASSA-PKCS1-v1_5' }, + publicKey, + sig, + msg instanceof Uint8Array ? msg : msg.subarray() + ) + options?.signal?.throwIfAborted() + + return result +} + +async function exportKey (pair: CryptoKeyPair, options?: AbortOptions): Promise<[JsonWebKey, JsonWebKey]> { + if (pair.privateKey == null || pair.publicKey == null) { + throw new InvalidParametersError('Private and public key are required') + } + + const result = await Promise.all([ + webcrypto.get().subtle.exportKey('jwk', pair.privateKey), + webcrypto.get().subtle.exportKey('jwk', pair.publicKey) + ]) + options?.signal?.throwIfAborted() + + return result +} + +export function rsaKeySize (jwk: JsonWebKey): number { + if (jwk.kty !== 'RSA') { + throw new InvalidParametersError('invalid key type') + } else if (jwk.n == null) { + throw new InvalidParametersError('invalid key modulus') + } + const bytes = uint8ArrayFromString(jwk.n, 'base64url') + return bytes.length * 8 +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/index.ts new file mode 100644 index 000000000..96d648f96 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/index.ts @@ -0,0 +1,78 @@ +import crypto from 'node:crypto' +import { promisify } from 'node:util' +import { InvalidParametersError } from '@libp2p/interface' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import randomBytes from '../../random-bytes.js' +import * as utils from './utils.js' +import type { JWKKeyPair } from '../interface.js' +import type { AbortOptions } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +const keypair = promisify(crypto.generateKeyPair) + +export const RSAES_PKCS1_V1_5_OID = '1.2.840.113549.1.1.1' + +export { utils } + +export async function generateRSAKey (bits: number, options?: AbortOptions): Promise { + // @ts-expect-error node types are missing jwk as a format + const key = await keypair('rsa', { + modulusLength: bits, + publicKeyEncoding: { type: 'pkcs1', format: 'jwk' }, + privateKeyEncoding: { type: 'pkcs1', format: 'jwk' } + }) + options?.signal?.throwIfAborted() + + return { + // @ts-expect-error node types are missing jwk as a format + privateKey: key.privateKey, + // @ts-expect-error node types are missing jwk as a format + publicKey: key.publicKey + } +} + +export { randomBytes as getRandomValues } + +export function hashAndSign (key: JsonWebKey, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array { + options?.signal?.throwIfAborted() + + const hash = crypto.createSign('RSA-SHA256') + + if (msg instanceof Uint8Array) { + hash.update(msg) + } else { + for (const buf of msg) { + hash.update(buf) + } + } + + // @ts-expect-error node types are missing jwk as a format + return hash.sign({ format: 'jwk', key }) +} + +export function hashAndVerify (key: JsonWebKey, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): boolean { + options?.signal?.throwIfAborted() + + const hash = crypto.createVerify('RSA-SHA256') + + if (msg instanceof Uint8Array) { + hash.update(msg) + } else { + for (const buf of msg) { + hash.update(buf) + } + } + + // @ts-expect-error node types are missing jwk as a format + return hash.verify({ format: 'jwk', key }, sig) +} + +export function rsaKeySize (jwk: JsonWebKey): number { + if (jwk.kty !== 'RSA') { + throw new InvalidParametersError('Invalid key type') + } else if (jwk.n == null) { + throw new InvalidParametersError('Invalid key modulus') + } + const modulus = uint8ArrayFromString(jwk.n, 'base64url') + return modulus.length * 8 +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/rsa.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/rsa.ts new file mode 100644 index 000000000..5c7c0aa6f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/rsa.ts @@ -0,0 +1,83 @@ +import { base58btc } from 'multiformats/bases/base58' +import { CID } from 'multiformats/cid' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { hashAndSign, utils, hashAndVerify } from './index.js' +import type { RSAPublicKey as RSAPublicKeyInterface, RSAPrivateKey as RSAPrivateKeyInterface, AbortOptions } from '@libp2p/interface' +import type { Digest } from 'multiformats/hashes/digest' +import type { Uint8ArrayList } from 'uint8arraylist' + +export class RSAPublicKey implements RSAPublicKeyInterface { + public readonly type = 'RSA' + public readonly jwk: JsonWebKey + private _raw?: Uint8Array + private readonly _multihash: Digest<18, number> + + constructor (jwk: JsonWebKey, digest: Digest<18, number>) { + this.jwk = jwk + this._multihash = digest + } + + get raw (): Uint8Array { + if (this._raw == null) { + this._raw = utils.jwkToPkix(this.jwk) + } + + return this._raw + } + + toMultihash (): Digest<18, number> { + return this._multihash + } + + toCID (): CID { + return CID.createV1(114, this._multihash) + } + + toString (): string { + return base58btc.encode(this.toMultihash().bytes).substring(1) + } + + equals (key?: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + verify (data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): boolean | Promise { + return hashAndVerify(this.jwk, sig, data, options) + } +} + +export class RSAPrivateKey implements RSAPrivateKeyInterface { + public readonly type = 'RSA' + public readonly jwk: JsonWebKey + private _raw?: Uint8Array + public readonly publicKey: RSAPublicKey + + constructor (jwk: JsonWebKey, publicKey: RSAPublicKey) { + this.jwk = jwk + this.publicKey = publicKey + } + + get raw (): Uint8Array { + if (this._raw == null) { + this._raw = utils.jwkToPkcs1(this.jwk) + } + + return this._raw + } + + equals (key: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + sign (message: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise { + return hashAndSign(this.jwk, message, options) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/utils.ts new file mode 100644 index 000000000..08e665a5a --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/rsa/utils.ts @@ -0,0 +1,214 @@ +import { InvalidParametersError, InvalidPublicKeyError } from '@libp2p/interface' +import { sha256 } from '@noble/hashes/sha256' +import { create } from 'multiformats/hashes/digest' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import * as pb from '../keys.js' +import { decodeDer, encodeBitString, encodeInteger, encodeSequence } from './der.js' +import { RSAPrivateKey as RSAPrivateKeyClass, RSAPublicKey as RSAPublicKeyClass } from './rsa.js' +import { generateRSAKey, rsaKeySize } from './index.js' +import type { JWKKeyPair } from '../interface.js' +import type { RSAPrivateKey, RSAPublicKey } from '@libp2p/interface' +import type { Digest } from 'multiformats/hashes/digest' + +export const MAX_RSA_KEY_SIZE = 8192 +const SHA2_256_CODE = 0x12 +const MAX_RSA_JWK_SIZE = 1062 + +const RSA_ALGORITHM_IDENTIFIER = Uint8Array.from([ + 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 +]) + +/** + * Convert a PKCS#1 in ASN1 DER format to a JWK private key + */ +export function pkcs1ToJwk (bytes: Uint8Array): JsonWebKey { + const message = decodeDer(bytes) + + return pkcs1MessageToJwk(message) +} + +/** + * Convert a PKCS#1 in ASN1 DER format to a JWK private key + */ +export function pkcs1MessageToJwk (message: any): JsonWebKey { + return { + n: uint8ArrayToString(message[1], 'base64url'), + e: uint8ArrayToString(message[2], 'base64url'), + d: uint8ArrayToString(message[3], 'base64url'), + p: uint8ArrayToString(message[4], 'base64url'), + q: uint8ArrayToString(message[5], 'base64url'), + dp: uint8ArrayToString(message[6], 'base64url'), + dq: uint8ArrayToString(message[7], 'base64url'), + qi: uint8ArrayToString(message[8], 'base64url'), + kty: 'RSA' + } +} + +/** + * Convert a JWK private key into PKCS#1 in ASN1 DER format + */ +export function jwkToPkcs1 (jwk: JsonWebKey): Uint8Array { + if (jwk.n == null || jwk.e == null || jwk.d == null || jwk.p == null || jwk.q == null || jwk.dp == null || jwk.dq == null || jwk.qi == null) { + throw new InvalidParametersError('JWK was missing components') + } + + return encodeSequence([ + encodeInteger(Uint8Array.from([0])), + encodeInteger(uint8ArrayFromString(jwk.n, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.e, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.d, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.p, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.q, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.dp, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.dq, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.qi, 'base64url')) + ]).subarray() +} + +/** + * Convert a PKIX in ASN1 DER format to a JWK public key + */ +export function pkixToJwk (bytes: Uint8Array): JsonWebKey { + const message = decodeDer(bytes, { + offset: 0 + }) + + return pkixMessageToJwk(message) +} + +export function pkixMessageToJwk (message: any): JsonWebKey { + const keys = decodeDer(message[1], { + offset: 0 + }) + + // this looks fragile but DER is a canonical format so we are safe to have + // deeply property chains like this + return { + kty: 'RSA', + n: uint8ArrayToString( + keys[0], + 'base64url' + ), + e: uint8ArrayToString( + keys[1], + 'base64url' + ) + } +} + +/** + * Convert a JWK public key to PKIX in ASN1 DER format + */ +export function jwkToPkix (jwk: JsonWebKey): Uint8Array { + if (jwk.n == null || jwk.e == null) { + throw new InvalidParametersError('JWK was missing components') + } + + const subjectPublicKeyInfo = encodeSequence([ + RSA_ALGORITHM_IDENTIFIER, + encodeBitString( + encodeSequence([ + encodeInteger(uint8ArrayFromString(jwk.n, 'base64url')), + encodeInteger(uint8ArrayFromString(jwk.e, 'base64url')) + ]) + ) + ]) + + return subjectPublicKeyInfo.subarray() +} + +/** + * Turn PKCS#1 DER bytes into a PrivateKey + */ +export function pkcs1ToRSAPrivateKey (bytes: Uint8Array): RSAPrivateKey { + const message = decodeDer(bytes) + + return pkcs1MessageToRSAPrivateKey(message) +} + +/** + * Turn PKCS#1 DER bytes into a PrivateKey + */ +export function pkcs1MessageToRSAPrivateKey (message: any): RSAPrivateKey { + const jwk = pkcs1MessageToJwk(message) + + return jwkToRSAPrivateKey(jwk) +} + +/** + * Turn a PKIX message into a PublicKey + */ +export function pkixToRSAPublicKey (bytes: Uint8Array, digest?: Digest<18, number>): RSAPublicKey { + if (bytes.byteLength >= MAX_RSA_JWK_SIZE) { + throw new InvalidPublicKeyError('Key size is too large') + } + + const message = decodeDer(bytes, { + offset: 0 + }) + + return pkixMessageToRSAPublicKey(message, bytes, digest) +} + +export function pkixMessageToRSAPublicKey (message: any, bytes: Uint8Array, digest?: Digest<18, number>): RSAPublicKey { + const jwk = pkixMessageToJwk(message) + + if (digest == null) { + const hash = sha256(pb.PublicKey.encode({ + Type: pb.KeyType.RSA, + Data: bytes + })) + digest = create(SHA2_256_CODE, hash) + } + + return new RSAPublicKeyClass(jwk, digest) +} + +export function jwkToRSAPrivateKey (jwk: JsonWebKey): RSAPrivateKey { + if (rsaKeySize(jwk) > MAX_RSA_KEY_SIZE) { + throw new InvalidParametersError('Key size is too large') + } + + const keys = jwkToJWKKeyPair(jwk) + const hash = sha256(pb.PublicKey.encode({ + Type: pb.KeyType.RSA, + Data: jwkToPkix(keys.publicKey) + })) + const digest = create(SHA2_256_CODE, hash) + + return new RSAPrivateKeyClass(keys.privateKey, new RSAPublicKeyClass(keys.publicKey, digest)) +} + +export async function generateRSAKeyPair (bits: number): Promise { + if (bits > MAX_RSA_KEY_SIZE) { + throw new InvalidParametersError('Key size is too large') + } + + const keys = await generateRSAKey(bits) + const hash = sha256(pb.PublicKey.encode({ + Type: pb.KeyType.RSA, + Data: jwkToPkix(keys.publicKey) + })) + const digest = create(SHA2_256_CODE, hash) + + return new RSAPrivateKeyClass(keys.privateKey, new RSAPublicKeyClass(keys.publicKey, digest)) +} + +/** + * Takes a jwk key and returns a JWK KeyPair + */ +export function jwkToJWKKeyPair (key: JsonWebKey): JWKKeyPair { + if (key == null) { + throw new InvalidParametersError('Missing key parameter') + } + + return { + privateKey: key, + publicKey: { + kty: key.kty, + n: key.n, + e: key.e + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/index.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/index.browser.ts new file mode 100644 index 000000000..51e36e41d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/index.browser.ts @@ -0,0 +1,69 @@ +import { secp256k1 as secp } from '@noble/curves/secp256k1' +import { sha256 } from 'multiformats/hashes/sha2' +import { SigningError, VerificationError } from '../../errors.js' +import { isPromise } from '../../util.js' +import type { AbortOptions } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +const PUBLIC_KEY_BYTE_LENGTH = 33 +const PRIVATE_KEY_BYTE_LENGTH = 32 + +export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength } +export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength } + +/** + * Hash and sign message with private key + */ +export function hashAndSign (key: Uint8Array, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise { + const p = sha256.digest(msg instanceof Uint8Array ? msg : msg.subarray()) + + if (isPromise(p)) { + return p + .then(({ digest }) => { + options?.signal?.throwIfAborted() + return secp.sign(digest, key).toDERRawBytes() + }) + .catch(err => { + if (err.name === 'AbortError') { + throw err + } + + throw new SigningError(String(err)) + }) + } + + try { + return secp.sign(p.digest, key).toDERRawBytes() + } catch (err) { + throw new SigningError(String(err)) + } +} + +/** + * Hash message and verify signature with public key + */ +export function hashAndVerify (key: Uint8Array, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): boolean | Promise { + const p = sha256.digest(msg instanceof Uint8Array ? msg : msg.subarray()) + + if (isPromise(p)) { + return p + .then(({ digest }) => { + options?.signal?.throwIfAborted() + return secp.verify(sig, digest, key) + }) + .catch(err => { + if (err.name === 'AbortError') { + throw err + } + + throw new VerificationError(String(err)) + }) + } + + try { + options?.signal?.throwIfAborted() + return secp.verify(sig, p.digest, key) + } catch (err) { + throw new VerificationError(String(err)) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/index.ts new file mode 100644 index 000000000..cc55521ed --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/index.ts @@ -0,0 +1,61 @@ +import crypto from 'node:crypto' +import { secp256k1 as secp } from '@noble/curves/secp256k1' +import { SigningError, VerificationError } from '../../errors.js' +import type { AbortOptions } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +const PUBLIC_KEY_BYTE_LENGTH = 33 +const PRIVATE_KEY_BYTE_LENGTH = 32 + +export { PUBLIC_KEY_BYTE_LENGTH as publicKeyLength } +export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength } + +/** + * Hash and sign message with private key + */ +export function hashAndSign (key: Uint8Array, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array { + options?.signal?.throwIfAborted() + + const hash = crypto.createHash('sha256') + + if (msg instanceof Uint8Array) { + hash.update(msg) + } else { + for (const buf of msg) { + hash.update(buf) + } + } + + const digest = hash.digest() + + try { + const signature = secp.sign(digest, key) + return signature.toDERRawBytes() + } catch (err) { + throw new SigningError(String(err)) + } +} + +/** + * Hash message and verify signature with public key + */ +export function hashAndVerify (key: Uint8Array, sig: Uint8Array, msg: Uint8Array | Uint8ArrayList, options?: AbortOptions): boolean { + options?.signal?.throwIfAborted() + const hash = crypto.createHash('sha256') + + if (msg instanceof Uint8Array) { + hash.update(msg) + } else { + for (const buf of msg) { + hash.update(buf) + } + } + + const digest = hash.digest() + + try { + return secp.verify(sig, digest, key) + } catch (err) { + throw new VerificationError(String(err)) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/secp256k1.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/secp256k1.ts new file mode 100644 index 000000000..3c0140787 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/secp256k1.ts @@ -0,0 +1,68 @@ +import { base58btc } from 'multiformats/bases/base58' +import { CID } from 'multiformats/cid' +import { identity } from 'multiformats/hashes/identity' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { publicKeyToProtobuf } from '../index.js' +import { validateSecp256k1PublicKey, compressSecp256k1PublicKey, computeSecp256k1PublicKey, validateSecp256k1PrivateKey } from './utils.js' +import { hashAndVerify, hashAndSign } from './index.js' +import type { Secp256k1PublicKey as Secp256k1PublicKeyInterface, Secp256k1PrivateKey as Secp256k1PrivateKeyInterface, AbortOptions } from '@libp2p/interface' +import type { Digest } from 'multiformats/hashes/digest' +import type { Uint8ArrayList } from 'uint8arraylist' + +export class Secp256k1PublicKey implements Secp256k1PublicKeyInterface { + public readonly type = 'secp256k1' + public readonly raw: Uint8Array + public readonly _key: Uint8Array + + constructor (key: Uint8Array) { + this._key = validateSecp256k1PublicKey(key) + this.raw = compressSecp256k1PublicKey(this._key) + } + + toMultihash (): Digest<0x0, number> { + return identity.digest(publicKeyToProtobuf(this)) + } + + toCID (): CID { + return CID.createV1(114, this.toMultihash()) + } + + toString (): string { + return base58btc.encode(this.toMultihash().bytes).substring(1) + } + + equals (key: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + verify (data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): boolean { + return hashAndVerify(this._key, sig, data, options) + } +} + +export class Secp256k1PrivateKey implements Secp256k1PrivateKeyInterface { + public readonly type = 'secp256k1' + public readonly raw: Uint8Array + public readonly publicKey: Secp256k1PublicKey + + constructor (key: Uint8Array, publicKey?: Uint8Array) { + this.raw = validateSecp256k1PrivateKey(key) + this.publicKey = new Secp256k1PublicKey(publicKey ?? computeSecp256k1PublicKey(key)) + } + + equals (key?: any): boolean { + if (key == null || !(key.raw instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.raw, key.raw) + } + + sign (message: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise { + return hashAndSign(this.raw, message, options) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/utils.ts new file mode 100644 index 000000000..a6f3b7e54 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/keys/secp256k1/utils.ts @@ -0,0 +1,63 @@ +import { InvalidPrivateKeyError, InvalidPublicKeyError } from '@libp2p/interface' +import { secp256k1 as secp } from '@noble/curves/secp256k1' +import { Secp256k1PublicKey as Secp256k1PublicKeyClass, Secp256k1PrivateKey as Secp256k1PrivateKeyClass } from './secp256k1.js' +import type { Secp256k1PublicKey, Secp256k1PrivateKey } from '@libp2p/interface' + +const PRIVATE_KEY_BYTE_LENGTH = 32 + +export { PRIVATE_KEY_BYTE_LENGTH as privateKeyLength } + +export function unmarshalSecp256k1PrivateKey (bytes: Uint8Array): Secp256k1PrivateKey { + return new Secp256k1PrivateKeyClass(bytes) +} + +export function unmarshalSecp256k1PublicKey (bytes: Uint8Array): Secp256k1PublicKey { + return new Secp256k1PublicKeyClass(bytes) +} + +export async function generateSecp256k1KeyPair (): Promise { + const privateKeyBytes = generateSecp256k1PrivateKey() + return new Secp256k1PrivateKeyClass(privateKeyBytes) +} + +export function compressSecp256k1PublicKey (key: Uint8Array): Uint8Array { + const point = secp.ProjectivePoint.fromHex(key).toRawBytes(true) + return point +} + +export function decompressSecp256k1PublicKey (key: Uint8Array): Uint8Array { + const point = secp.ProjectivePoint.fromHex(key).toRawBytes(false) + return point +} + +export function validateSecp256k1PrivateKey (key: Uint8Array): Uint8Array { + try { + secp.getPublicKey(key, true) + + return key + } catch (err) { + throw new InvalidPrivateKeyError(String(err)) + } +} + +export function validateSecp256k1PublicKey (key: Uint8Array): Uint8Array { + try { + secp.ProjectivePoint.fromHex(key) + + return key + } catch (err) { + throw new InvalidPublicKeyError(String(err)) + } +} + +export function computeSecp256k1PublicKey (privateKey: Uint8Array): Uint8Array { + try { + return secp.getPublicKey(privateKey, true) + } catch (err) { + throw new InvalidPrivateKeyError(String(err)) + } +} + +export function generateSecp256k1PrivateKey (): Uint8Array { + return secp.utils.randomPrivateKey() +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/pbkdf2.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/pbkdf2.ts new file mode 100644 index 000000000..a90dafc7b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/pbkdf2.ts @@ -0,0 +1,41 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { pbkdf2 as pbkdf2Sync } from '@noble/hashes/pbkdf2' +import { sha1 } from '@noble/hashes/sha1' +import { sha256 } from '@noble/hashes/sha256' +import { sha512 } from '@noble/hashes/sha512' +import { base64 } from 'multiformats/bases/base64' + +/** + * Maps an IPFS hash name to its @noble/hashes equivalent. + * + * See https://github.com/multiformats/multihash/blob/master/hashtable.csv + * + * @private + */ +const hashName = { + sha1, + 'sha2-256': sha256, + 'sha2-512': sha512 +} + +/** + * Computes the Password-Based Key Derivation Function 2. + */ +export default function pbkdf2 (password: string, salt: string | Uint8Array, iterations: number, keySize: number, hash: string): string { + if (hash !== 'sha1' && hash !== 'sha2-256' && hash !== 'sha2-512') { + const types = Object.keys(hashName).join(' / ') + throw new InvalidParametersError(`Hash '${hash}' is unknown or not supported. Must be ${types}`) + } + + const hasher = hashName[hash] + const dek = pbkdf2Sync( + hasher, + password, + salt, { + c: iterations, + dkLen: keySize + } + ) + + return base64.encode(dek).substring(1) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/random-bytes.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/random-bytes.ts new file mode 100644 index 000000000..e1a3d208f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/random-bytes.ts @@ -0,0 +1,12 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { randomBytes as randB } from '@noble/hashes/utils' + +/** + * Generates a Uint8Array with length `number` populated by random bytes + */ +export default function randomBytes (length: number): Uint8Array { + if (isNaN(length) || length <= 0) { + throw new InvalidParametersError('random bytes length must be a Number bigger than 0') + } + return randB(length) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/util.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/util.ts new file mode 100644 index 000000000..fa7f67455 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/util.ts @@ -0,0 +1,26 @@ +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' + +export function base64urlToBuffer (str: string, len?: number): Uint8Array { + let buf = uint8ArrayFromString(str, 'base64urlpad') + + if (len != null) { + if (buf.length > len) { + throw new Error('byte array longer than desired length') + } + + buf = uint8ArrayConcat([new Uint8Array(len - buf.length), buf]) + } + + return buf +} + +export function isPromise (thing: any): thing is Promise { + if (thing == null) { + return false + } + + return typeof thing.then === 'function' && + typeof thing.catch === 'function' && + typeof thing.finally === 'function' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/index.ts new file mode 100644 index 000000000..2c7b2df55 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/index.ts @@ -0,0 +1,3 @@ +import webcrypto from './webcrypto.js' + +export default webcrypto diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/webcrypto.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/webcrypto.browser.ts new file mode 100644 index 000000000..390296137 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/webcrypto.browser.ts @@ -0,0 +1,23 @@ +/* eslint-env browser */ + +import { WebCryptoMissingError } from '../errors.js' + +// Check native crypto exists and is enabled (In insecure context `self.crypto` +// exists but `self.crypto.subtle` does not). +export default { + get (win = globalThis) { + const nativeCrypto = win.crypto + + if (nativeCrypto?.subtle == null) { + throw new WebCryptoMissingError( + 'Missing Web Crypto API. ' + + 'The most likely cause of this error is that this page is being accessed ' + + 'from an insecure context (i.e. not HTTPS). For more information and ' + + 'possible resolutions see ' + + 'https://github.com/libp2p/js-libp2p/blob/main/packages/crypto/README.md#web-crypto-api' + ) + } + + return nativeCrypto + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/webcrypto.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/webcrypto.ts new file mode 100644 index 000000000..d583e7bd6 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/src/webcrypto/webcrypto.ts @@ -0,0 +1,11 @@ +/* eslint-env browser */ + +import { webcrypto } from 'crypto' + +// globalThis `SubtleCrypto` shipped in node.js 19.x, Electron currently uses +// v18.x so this override file is necessary until Electron updates +export default { + get (win = globalThis) { + return webcrypto + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/typedoc.json new file mode 100644 index 000000000..c9ed8bd69 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/crypto/typedoc.json @@ -0,0 +1,10 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts", + "./src/ciphers/index.ts", + "./src/hmac/index.ts", + "./src/keys/index.ts", + "./src/webcrypto/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/README.md new file mode 100644 index 000000000..554f86ae7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/README.md @@ -0,0 +1,52 @@ +# @libp2p/interface-internal + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> Interfaces implemented by internal libp2p components + +# About + + + +This module serves as the entry point for `@libp2p/interface-internal`, +exporting key components such as `AddressManager`, `ConnectionManager`, +`RandomWalk`, `Registrar`, and `TransportManager`. + +These interfaces and classes define the core internal behaviors of libp2p. + +# Install + +```console +$ npm i @libp2p/interface-internal +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/interface-internal/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/interface-internal/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/package.json new file mode 100644 index 000000000..bdc54c2b0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/package.json @@ -0,0 +1,50 @@ +{ + "name": "@libp2p/interface-internal", + "version": "2.3.18", + "description": "Interfaces implemented by internal libp2p components", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/interface-internal#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "interface", + "libp2p" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build" + }, + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/peer-collections": "^6.0.34", + "@multiformats/multiaddr": "^12.4.4", + "progress-events": "^1.0.1" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/address-manager.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/address-manager.ts new file mode 100644 index 000000000..cb325f276 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/address-manager.ts @@ -0,0 +1,174 @@ +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * The type of address: + * + * - 'transport' a listen address supplied by a transport + * - 'announce' a pre-configured announce address + * - 'observed' a peer reported this as a public address + * - 'dns-mapping' a DNS address dynamically mapped to one or more public addresses + * - 'ip-mapping' an external IP address dynamically mapped to a LAN address + */ +export type AddressType = 'transport' | 'announce' | 'observed' | 'dns-mapping' | 'ip-mapping' + +/** + * An address that has been configured or detected + */ +export interface NodeAddress { + /** + * The multiaddr that represents the address + */ + multiaddr: Multiaddr + + /** + * Dynamically configured addresses such as observed or IP/DNS mapped ones + * must be verified as valid by AutoNAT or some other means before the current + * node will add them to it's peer record and share them with peers. + * + * When this value is true, it's safe to share the address. + */ + verified: boolean + + /** + * The timestamp at which the address was last verified + */ + lastVerified?: number + + /** + * A millisecond timestamp after which this address should be reverified + */ + expires: number + + /** + * The source of this address + */ + type: AddressType +} + +export interface ConfirmAddressOptions { + /** + * Override the TTL of the observed address verification + */ + ttl?: number + + /** + * Allows hinting which type of address this is + */ + type?: AddressType +} + +/** + * The `AddressManager` provides an interface for managing peer addresses + * in libp2p. It supports handling multiple types of addresses, verifying their validity, + * and storing mappings between internal and external addresses. + */ +export interface AddressManager { + /** + * Get peer listen multiaddrs + * + * @returns An array of `Multiaddr` objects representing listen addresses. + */ + getListenAddrs(): Multiaddr[] + + /** + * Get peer announcing multiaddrs + * + * @returns An array of `Multiaddr` objects representing announce addresses. + */ + getAnnounceAddrs(): Multiaddr[] + + /** + * Get observed multiaddrs - these addresses may not have been confirmed as + * publicly dialable yet + * + * @returns An array of `Multiaddr` objects representing observed addresses. + */ + getObservedAddrs(): Multiaddr[] + + /** + * Signal that we have confidence an observed multiaddr is publicly dialable - + * this will make it appear in the output of `getAddresses()` + * + * @param addr - The observed address. + * @param options - Additional options for confirmation. + */ + confirmObservedAddr(addr: Multiaddr, options?: ConfirmAddressOptions): void + + /** + * Signal that we do not have confidence an observed multiaddr is publicly dialable - + * this will remove it from the output of `getObservedAddrs()` + * + * @param addr - The observed address to remove. + */ + removeObservedAddr(addr: Multiaddr): void + + /** + * Add peer observed addresses. These will then appear in the output of `getObservedAddrs()` + * but not `getAddresses()` until their dialability has been confirmed via a call to + * confirmObservedAddr. + * + * @param addr - The observed address to add. + */ + addObservedAddr(addr: Multiaddr): void + + /** + * Get the current node's addresses + * + * @returns An array of `Multiaddr` objects representing node addresses. + */ + getAddresses(): Multiaddr[] + + /** + * Return all known addresses with metadata + * + * @returns An array of `NodeAddress` objects. + */ + getAddressesWithMetadata(): NodeAddress[] + + /** + * Adds a mapping between one or more IP addresses and a domain name - when + * `getAddresses` is invoked, where the IP addresses are present in a + * multiaddr, an additional multiaddr will be added with `ip4` and `ip6` + * tuples replaced with `dns4` and `dns6 ones respectively. + * + * @param domain - The domain name to map. + * @param ipAddresses - The associated IP addresses. + */ + addDNSMapping(domain: string, ipAddresses: string[]): void + + /** + * Remove a mapping previously added with `addDNSMapping`. + * + * @param domain - The domain name mapping to remove. + */ + removeDNSMapping(domain: string): void + + /** + * Add a publicly routable address/port/protocol tuple that this node is + * reachable on. Where this node listens on a link-local (e.g. LAN) address + * with the same protocol for any transport, an additional listen address will + * be added with the IP and port replaced with this IP and port. + * + * It's possible to add a IPv6 address here and have it added to the address + * list, this is for the case when a router has an external IPv6 address with + * port forwarding configured, but it does IPv6 -> IPv4 NAT. + * + * @param internalIp - The internal IP address. + * @param internalPort - The internal port number. + * @param externalIp - The external IP address. + * @param externalPort - The external port number (optional). + * @param protocol - The transport protocol (`tcp` or `udp`). + */ + addPublicAddressMapping (internalIp: string, internalPort: number, externalIp: string, externalPort?: number, protocol?: 'tcp' | 'udp'): void + + /** + * Remove a publicly routable address that this node is no longer reachable on + * + * @param internalIp - The internal IP address. + * @param internalPort - The internal port number. + * @param externalIp - The external IP address. + * @param externalPort - The external port number (optional). + * @param protocol - The transport protocol (`tcp` or `udp`). + */ + removePublicAddressMapping (internalIp: string, internalPort: number, externalIp: string, externalPort?: number, protocol?: 'tcp' | 'udp'): void +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/connection-manager.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/connection-manager.ts new file mode 100644 index 000000000..adde00417 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/connection-manager.ts @@ -0,0 +1,131 @@ +import type { AbortOptions, PendingDial, Connection, MultiaddrConnection, PeerId, IsDialableOptions, OpenConnectionProgressEvents } from '@libp2p/interface' +import type { PeerMap } from '@libp2p/peer-collections' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { ProgressOptions } from 'progress-events' + +/** + * Options for opening a connection to a remote peer. + */ +export interface OpenConnectionOptions extends AbortOptions, ProgressOptions { + /** + * Connection requests with a higher priority will be executed before those + * with a lower priority. + * + * @default 50 + */ + priority?: number + + /** + * When opening a connection to a remote peer, if a connection already exists + * it will be returned instead of creating a new connection. Pass true here + * to override that and dial a new connection anyway. + * + * @default false + */ + force?: boolean + + /** + * By default a newly opened outgoing connection operates in initiator mode + * during negotiation of encryption/muxing protocols using multistream-select. + * + * In some cases such as when the dialer is trying to achieve TCP Simultaneous + * Connect using the DCUtR protocol, it may wish to act in responder mode, if + * so pass `false` here. + * + * @default true + */ + initiator?: boolean +} + +/** + * The `ConnectionManager` handles managing connections between peers in a libp2p network. + * It provides methods for opening, closing, and querying connections.This also provides methods + * for accessing the dial queue. + */ +export interface ConnectionManager { + /** + * Return connections, optionally filtering by a PeerId + * + * @param peerId - The PeerId to filter connections (optional). + * @returns An array of active `Connection` objects. + */ + getConnections(peerId?: PeerId): Connection[] + + /** + * Return a map of all connections with their associated PeerIds + * + * @returns A `PeerMap` containing `Connection[]` objects. + */ + getConnectionsMap(): PeerMap + + /** + * Returns the configured maximum number of connections this connection + * manager will accept + * + * @returns The maximum connection limit. + */ + getMaxConnections(): number + + /** + * Update the maximum number of connections that are accepted - setting this + * to a smaller value than the current setting will cause connections to be + * pruned. + */ + setMaxConnections(maxConnections: number): void + + /** + * Open a connection to a remote peer + * + * @param peer - The target `PeerId`, `Multiaddr`, or an array of `Multiaddr`s. + * @param options - Optional parameters for connection handling. + * @returns A promise that resolves to a `Connection` object. + */ + openConnection(peer: PeerId | Multiaddr | Multiaddr[], options?: OpenConnectionOptions): Promise + + /** + * Close our connections to a peer + * + * @param peer - The `PeerId` whose connections should be closed. + * @param options - Optional abort options. + * @returns A promise that resolves once the connections are closed. + */ + closeConnections(peer: PeerId, options?: AbortOptions): Promise + + /** + * Invoked after an incoming connection is opened but before PeerIds are + * exchanged, this lets the ConnectionManager check we have sufficient + * resources to accept the connection in which case it will return true, + * otherwise it will return false. + * + * @param maConn - The multiaddr connection to evaluate. + * @returns `true` if the connection can be accepted, `false` otherwise. + */ + acceptIncomingConnection(maConn: MultiaddrConnection): boolean + + /** + * Invoked after upgrading an inbound multiaddr connection has finished + */ + afterUpgradeInbound(): void + + /** + * Return the list of in-progress or queued dials + * + * @returns An array of `PendingDial` objects. + */ + getDialQueue(): PendingDial[] + + /** + * Given the current node configuration, returns a promise of `true` or + * `false` if the node would attempt to dial the passed multiaddr. + * + * This means a relevant transport is configured, and the connection gater + * would not block the dial attempt. + * + * This may involve resolving DNS addresses so you should pass an AbortSignal. + * + * @param multiaddr - The target multiaddr or an array of multiaddrs. + * @param options - Optional parameters for dialability check. + * @returns A promise that resolves to `true` if the multiaddr is dialable, `false` otherwise. + */ + isDialable(multiaddr: Multiaddr | Multiaddr[], options?: IsDialableOptions): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/index.ts new file mode 100644 index 000000000..76ae8100a --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/index.ts @@ -0,0 +1,15 @@ +/** + * @packageDocumentation + * + * This module serves as the entry point for `@libp2p/interface-internal`, + * exporting key components such as `AddressManager`, `ConnectionManager`, + * `RandomWalk`, `Registrar`, and `TransportManager`. + * + * These interfaces and classes define the core internal behaviors of libp2p. + */ + +export * from './address-manager.js' +export * from './connection-manager.js' +export * from './random-walk.js' +export * from './registrar.js' +export * from './transport-manager.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/random-walk.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/random-walk.ts new file mode 100644 index 000000000..dc88b4cea --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/random-walk.ts @@ -0,0 +1,20 @@ +import type { AbortOptions, PeerInfo } from '@libp2p/interface' + +/** + * The `RandomWalk` component uses the libp2p peer routing to find arbitrary + * network peers. Consumers may then dial these peers, causing the Identify + * protocol to run and any registered topologies to be notified of their + * supported protocols. + */ +export interface RandomWalk { + /** + * Initiates a random walk for peer discovery. + * + * This method either begins a new random walk or joins an existing one. The process + * continues to find and return random peers until it is aborted. + * + * @param options - Optional `AbortOptions` to allow early termination of the walk. + * @returns An `AsyncGenerator` that yields discovered `PeerInfo` objects. + */ + walk(options?: AbortOptions): AsyncGenerator +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/registrar.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/registrar.ts new file mode 100644 index 000000000..d00d4b30f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/registrar.ts @@ -0,0 +1,96 @@ +import type { StreamHandler, StreamHandlerOptions, StreamHandlerRecord, Topology } from '@libp2p/interface' +import type { AbortOptions } from '@multiformats/multiaddr' + +export type { + /** + * @deprecated This type should be imported from @libp2p/interface directly + */ + StreamHandler, + + /** + * @deprecated This type should be imported from @libp2p/interface directly + */ + StreamHandlerOptions, + + /** + * @deprecated This type should be imported from @libp2p/interface directly + */ + StreamHandlerRecord +} + +/** + * The `Registrar` provides an interface for registering protocol handlers - + * these are invoked when remote peers open streams on the local node with the + * corresponding protocol name. + * + * It also allows configuring network topologies for a given protocol(s). The + * topology callbacks are invoked when a peer that supports those protocols + * connects or disconnects. + * + * The Identify protocol must be configured on the current node for topologies + * to function. + */ +export interface Registrar { + /** + * Retrieve the list of registered protocol handlers. + * + * @returns An array of protocol strings. + */ + getProtocols(): string[] + + /** + * Register a handler for a specific protocol. + * + * @param protocol - The protocol string (e.g., `/my-protocol/1.0.0`). + * @param handler - The function that handles incoming streams. + * @param options - Optional configuration options for the handler. + * @returns A promise that resolves once the handler is registered. + */ + handle(protocol: string, handler: StreamHandler, options?: StreamHandlerOptions): Promise + + /** + * Remove a registered protocol handler. + * + * @param protocol - The protocol to unhandle. + * @returns A promise that resolves once the handler is removed. + */ + unhandle(protocol: string, options?: AbortOptions): Promise + + /** + * Retrieve the registered handler for a given protocol. + * + * @param protocol - The protocol to query. + * @returns A `StreamHandlerRecord` containing the handler and options. + */ + getHandler(protocol: string): StreamHandlerRecord + + /** + * Register a topology handler for a protocol - the topology will be + * invoked when peers are discovered on the network that support the + * passed protocol. + * + * An id will be returned that can later be used to unregister the + * topology. + * + * @param protocol - The protocol to register. + * @param topology - The topology handler to register. + * @returns A promise resolving to a unique ID for the registered topology. + */ + register(protocol: string, topology: Topology, options?: AbortOptions): Promise + + /** + * Unregister a topology handler using its unique ID. + * + * @param id - The ID of the topology to unregister. + */ + unregister(id: string): void + + /** + * Retrieve all topology handlers that are interested in peers + * supporting a given protocol. + * + * @param protocol - The protocol to query. + * @returns An array of registered `Topology` handlers. + */ + getTopologies(protocol: string): Topology[] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/transport-manager.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/transport-manager.ts new file mode 100644 index 000000000..7b3a1f780 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/src/transport-manager.ts @@ -0,0 +1,101 @@ +import type { AbortOptions, Connection, Listener, Transport, TransportManagerDialProgressEvents } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { ProgressOptions } from 'progress-events' + +/** + * Options for dialing a connection using the `TransportManager`. + */ +export interface TransportManagerDialOptions extends AbortOptions, ProgressOptions { + +} + +/** + * The `TransportManager` handles the management of network transports, allowing + * opening connections or listening using specific transports, etc. + * + * This is a low-level component - any connections opened will not be managed by + * the `ConnectionManager` or included in any configured connection limits, etc. + * + * Most consumers will call `openConnection` on the `ConnectionManager` instead. + */ +export interface TransportManager { + /** + * Add a transport to the transport manager. + * + * @param transport - The transport instance to be added. + */ + add(transport: Transport): void + + /** + * Dial a multiaddr. Connections returned by this method will not be tracked + * by the connection manager so can cause memory leaks. If you need to dial + * a multiaddr, you may want to call openConnection on the connection manager + * instead. + * + * @param ma - The multiaddr to dial. + * @param options - Optional dial options. + * @returns A promise that resolves to a `Connection` object. + */ + dial(ma: Multiaddr, options?: TransportManagerDialOptions): Promise + + /** + * Return all addresses currently being listened on + * + * @returns An array of `Multiaddr` objects. + */ + getAddrs(): Multiaddr[] + + /** + * Return all registered transports + * + * @returns An array of `Transport` instances. + */ + getTransports(): Transport[] + + /** + * Return all listeners + * + * @returns An array of `Listener` instances. + */ + getListeners(): Listener[] + + /** + * Get the transport to dial a given multiaddr, if one has been configured + * + * @param ma - The target multiaddr. + * @returns A `Transport` instance if available, otherwise `undefined`. + */ + dialTransportForMultiaddr(ma: Multiaddr): Transport | undefined + + /** + * Get the transport to listen on a given multiaddr, if one has been + * configured + * + * @param ma - The target multiaddr. + * @returns A `Transport` instance if available, otherwise `undefined`. + */ + listenTransportForMultiaddr(ma: Multiaddr): Transport | undefined + + /** + * Listen on the passed multiaddrs + * + * @param addrs - An array of multiaddrs to listen on. + * @returns A promise that resolves once the transport is actively listening. + */ + listen(addrs: Multiaddr[]): Promise + + /** + * Remove a previously configured transport + * + * @param key - The transport key or identifier. + * @returns A promise that resolves once the transport is removed. + */ + remove(key: string): Promise + + /** + * Remove all transports + * + * @returns A promise that resolves once all transports are removed. + */ + removeAll(): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface-internal/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/README.md new file mode 100644 index 000000000..4a940d394 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/README.md @@ -0,0 +1,58 @@ +# @libp2p/interface + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> The interface implemented by a libp2p node + +# About + + + +Exports a `Libp2p` type for modules to use as a type argument. + +## Example + +```typescript +import type { Libp2p } from '@libp2p/interface' + +function doSomethingWithLibp2p (node: Libp2p) { + // ... +} +``` + +# Install + +```console +$ npm i @libp2p/interface +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/interface/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/interface/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/package.json new file mode 100644 index 000000000..95915b2db --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/package.json @@ -0,0 +1,56 @@ +{ + "name": "@libp2p/interface", + "version": "2.10.5", + "description": "The interface implemented by a libp2p node", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/interface#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "interface", + "libp2p" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build" + }, + "dependencies": { + "@multiformats/dns": "^1.0.6", + "@multiformats/multiaddr": "^12.4.4", + "it-pushable": "^3.2.3", + "main-event": "^1.0.1", + "multiformats": "^13.3.6", + "progress-events": "^1.0.1", + "uint8arraylist": "^2.4.8" + }, + "devDependencies": { + "aegir": "^47.0.14" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-encrypter.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-encrypter.ts new file mode 100644 index 000000000..ac4f55fc0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-encrypter.ts @@ -0,0 +1,65 @@ +import type { Uint8ArrayList } from 'uint8arraylist' +import type { AbortOptions, StreamMuxerFactory, MultiaddrConnection, PeerId, MessageStream } from './index.js' + +/** + * If the remote PeerId is known and passed as an option, the securing operation + * will throw if the remote peer cannot prove it has the private key that + * corresponds to the public key the remote PeerId is derived from. + */ +export interface SecureConnectionOptions extends AbortOptions { + remotePeer?: PeerId + + /** + * Some encryption protocols allow negotiating application protocols as part + * of the initial handshake. The negotiated stream muxer protocol will be + * included as part of the from the `secureOutbound`/`secureInbound` methods + * unless `false` is passed here. + */ + skipStreamMuxerNegotiation?: boolean +} + +/** + * A libp2p connection encrypter module must be compliant to this interface + * to ensure all exchanged data between two peers is encrypted. + */ +export interface ConnectionEncrypter { + protocol: string + + /** + * Encrypt outgoing data to the remote party. If the remote PeerId is known, + * pass it for extra verification, otherwise it will be determined during + * the handshake. + */ + secureOutbound (connection: Stream, options?: SecureConnectionOptions): Promise> + + /** + * Decrypt incoming data. If the remote PeerId is known, + * pass it for extra verification, otherwise it will be determined during + * the handshake + */ + secureInbound (connection: Stream, options?: SecureConnectionOptions): Promise> +} + +export interface SecuredConnection { + /** + * The decrypted data stream + */ + connection: MessageStream + + /** + * Any extension data transferred as part of the encryption handshake + */ + remoteExtensions?: Extension + + /** + * The identifier of the remote peer + */ + remotePeer: PeerId + + /** + * Some encryption protocols allow negotiating application protocols as part + * of the initial handshake. Where we are able to negotiated a stream muxer + * for the connection it will be returned here. + */ + streamMuxer?: StreamMuxerFactory +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-gater.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-gater.ts new file mode 100644 index 000000000..d5543c7df --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-gater.ts @@ -0,0 +1,127 @@ +import type { MultiaddrConnection, PeerId } from './index.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +export interface ConnectionGater { + /** + * denyDialPeer tests whether we're permitted to Dial the + * specified peer. + * + * This is called by the dialer.connectToPeer implementation before + * dialling a peer. + * + * Return true to prevent dialing the passed peer. + */ + denyDialPeer?(peerId: PeerId): Promise | boolean + + /** + * denyDialMultiaddr tests whether we're permitted to dial the specified + * multiaddr. + * + * This is called by the connection manager - if the peer id of the remote + * node is known it will be present in the multiaddr. + * + * Return true to prevent dialing the passed peer on the passed multiaddr. + */ + denyDialMultiaddr?(multiaddr: Multiaddr): Promise | boolean + + /** + * denyInboundConnection tests whether an incipient inbound connection is allowed. + * + * This is called by the upgrader, or by the transport directly (e.g. QUIC, + * Bluetooth), straight after it has accepted a connection from its socket. + * + * Return true to deny the incoming passed connection. + */ + denyInboundConnection?(maConn: MultiaddrConnection): Promise | boolean + + /** + * denyOutboundConnection tests whether an incipient outbound connection is allowed. + * + * This is called by the upgrader, or by the transport directly (e.g. QUIC, + * Bluetooth), straight after it has created a connection with its socket. + * + * Return true to deny the incoming passed connection. + */ + denyOutboundConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean + + /** + * denyInboundEncryptedConnection tests whether a given connection, now encrypted, + * is allowed. + * + * This is called by the upgrader, after it has performed the security + * handshake, and before it negotiates the muxer, or by the directly by the + * transport, at the exact same checkpoint. + * + * Return true to deny the passed secured connection. + */ + denyInboundEncryptedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean + + /** + * denyOutboundEncryptedConnection tests whether a given connection, now encrypted, + * is allowed. + * + * This is called by the upgrader, after it has performed the security + * handshake, and before it negotiates the muxer, or by the directly by the + * transport, at the exact same checkpoint. + * + * Return true to deny the passed secured connection. + */ + denyOutboundEncryptedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean + + /** + * denyInboundUpgradedConnection tests whether a fully capable connection is allowed. + * + * This is called after encryption has been negotiated and the connection has been + * multiplexed, if a multiplexer is configured. + * + * Return true to deny the passed upgraded connection. + */ + denyInboundUpgradedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean + + /** + * denyOutboundUpgradedConnection tests whether a fully capable connection is allowed. + * + * This is called after encryption has been negotiated and the connection has been + * multiplexed, if a multiplexer is configured. + * + * Return true to deny the passed upgraded connection. + */ + denyOutboundUpgradedConnection?(peerId: PeerId, maConn: MultiaddrConnection): Promise | boolean + + /** + * denyInboundRelayReservation tests whether a remote peer is allowed make a + * relay reservation on this node. + * + * Return true to deny the relay reservation. + */ + denyInboundRelayReservation?(source: PeerId): Promise | boolean + + /** + * denyOutboundRelayedConnection tests whether a remote peer is allowed to open a relayed + * connection to the destination node. + * + * This is invoked on the relay server when a source client with a reservation instructs + * the server to relay a connection to a destination peer. + * + * Return true to deny the relayed connection. + */ + denyOutboundRelayedConnection?(source: PeerId, destination: PeerId): Promise | boolean + + /** + * denyInboundRelayedConnection tests whether a remote peer is allowed to open a relayed + * connection to this node. + * + * This is invoked on the relay client when a remote relay has received an instruction to + * relay a connection to the client. + * + * Return true to deny the relayed connection. + */ + denyInboundRelayedConnection?(relay: PeerId, remotePeer: PeerId): Promise | boolean + + /** + * Used by the address book to filter passed addresses. + * + * Return true to allow storing the passed multiaddr for the passed peer. + */ + filterMultiaddrForPeer?(peer: PeerId, multiaddr: Multiaddr): Promise | boolean +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-protector.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-protector.ts new file mode 100644 index 000000000..0d6cde54c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection-protector.ts @@ -0,0 +1,9 @@ +import type { AbortOptions, MessageStream } from './index.ts' + +export interface ConnectionProtector { + /** + * Takes a MultiaddrConnection and creates a private encryption stream between + * the two peers from the shared key the Protector instance was created with. + */ + protect(connection: MessageStream, options?: AbortOptions): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection.ts new file mode 100644 index 000000000..280f12484 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/connection.ts @@ -0,0 +1,170 @@ +import type { AbortOptions, Logger, TypedEventTarget, Stream, MessageStreamEvents, PeerId, MultiaddrConnectionDirection, MultiaddrConnectionTimeline, MessageStreamStatus } from './index.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +export type ConnectionStatus = MessageStreamStatus + +/** + * Connection limits are present on connections that are only allowed to + * transfer a certain amount of bytes or be open for a certain number + * of seconds. + * + * These limits are applied by Circuit Relay v2 servers, for example and + * the connection will normally be closed abruptly if the limits are + * exceeded. + */ +export interface ConnectionLimits { + /** + * If present this is the number of bytes remaining that may be + * transferred over this connection + */ + bytes?: bigint + + /** + * If present this is the number of seconds that this connection will + * remain open for + */ + seconds?: number +} + +export interface NewStreamOptions extends AbortOptions { + /** + * If specified, and no handler has been registered with the registrar for the + * successfully negotiated protocol, use this as the max outbound stream limit + * for the protocol + */ + maxOutboundStreams?: number + + /** + * Opt-in to running over a limited connection - one that has restrictions + * on the amount of data that may be transferred or how long it may be open + * for. + * + * These limits are typically enforced by a relay server, if the protocol will + * be transferring a lot of data or the stream will be open for a long time + * consider upgrading to a direct connection before opening the stream. + * + * @default false + */ + runOnLimitedConnection?: boolean + + /** + * By default when negotiating a protocol the dialer writes then protocol name + * then reads the response. + * + * When a only a single protocol is being negotiated on an outbound stream, + * and the stream is written to before being read from, we can optimistically + * write the protocol name and the first chunk of data together in the first + * message. + * + * Reading and handling the protocol response is done asynchronously, which + * means we can skip a round trip on writing to newly opened streams which + * significantly reduces the time-to-first-byte on a stream. + * + * The side-effect of this is that the underlying stream won't negotiate the + * protocol until either data is written to or read from the stream so it will + * not be opened on the remote until this is done. + * + * Pass `false` here to optimistically write the protocol name and first chunk + * of data in the first message. + * + * If multiple protocols are being negotiated, negotiation is always completed + * in full before the stream is returned so this option has no effect. + * + * @default true + */ + negotiateFully?: boolean +} + +/** + * A Connection is a high-level representation of a connection + * to a remote peer that may have been secured by encryption and + * multiplexed, depending on the configuration of the nodes + * between which the connection is made. + */ +export interface Connection extends TypedEventTarget> { + /** + * The unique identifier for this connection + */ + id: string + + /** + * The address of the remote end of the connection + */ + remoteAddr: Multiaddr + + /** + * The id of the peer at the remote end of the connection + */ + remotePeer: PeerId + + /** + * A list of open streams on this connection + */ + streams: Stream[] + + /** + * Outbound connections are opened by the local node, inbound streams are opened by the remote + */ + direction: MultiaddrConnectionDirection + + /** + * When stream life cycle events occurred + */ + timeline: MultiaddrConnectionTimeline + + /** + * The multiplexer negotiated for this connection + */ + multiplexer?: string + + /** + * The encryption protocol negotiated for this connection + */ + encryption?: string + + /** + * The current status of the connection + */ + status: ConnectionStatus + + /** + * If present, this connection has limits applied to it, perhaps by an + * intermediate relay. Once the limits have been reached the connection will + * be closed by the relay. + */ + limits?: ConnectionLimits + + /** + * The time in milliseconds it takes to make a round trip to the remote peer. + * + * This is updated periodically by the connection monitor. + */ + rtt?: number + + /** + * The connection logger + */ + log: Logger + + /** + * Create a new stream on this connection and negotiate one of the passed protocols + */ + newStream(protocols: string | string[], options?: NewStreamOptions): Promise + + /** + * Gracefully close the connection. All queued data will be written to the + * underlying transport. + */ + close(options?: AbortOptions): Promise + + /** + * Immediately close the connection, any queued data will be discarded + */ + abort(err: Error): void +} + +export const connectionSymbol = Symbol.for('@libp2p/connection') + +export function isConnection (other: any): other is Connection { + return other != null && Boolean(other[connectionSymbol]) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/content-routing.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/content-routing.ts new file mode 100644 index 000000000..fea438cfe --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/content-routing.ts @@ -0,0 +1,98 @@ +import type { RoutingOptions } from './index.js' +import type { PeerInfo } from './peer-info.js' +import type { CID } from 'multiformats/cid' + +/** + * Any object that implements this Symbol as a property should return a + * Partial instance as the property value, similar to how + * `Symbol.Iterable` can be used to return an `Iterable` from an `Iterator`. + * + * @example + * + * ```TypeScript + * import { contentRoutingSymbol, ContentRouting } from '@libp2p/content-routing' + * + * class MyContentRouter implements ContentRouting { + * get [contentRoutingSymbol] () { + * return this + * } + * + * // ...other methods + * } + * ``` + */ +export const contentRoutingSymbol = Symbol.for('@libp2p/content-routing') + +/** + * Implementers of this interface can provide a ContentRouting implementation to + * interested callers. + */ +export interface ContentRoutingProvider { + [contentRoutingSymbol]: Partial +} + +export interface ContentRouting { + /** + * The implementation of this method should ensure that network peers know the + * caller can provide content that corresponds to the passed CID. + * + * @example + * + * ```TypeScript + * // ... + * await contentRouting.provide(cid) + * ``` + */ + provide(cid: CID, options?: RoutingOptions): Promise + + /** + * If network peers need to be periodically reminded that the caller can + * provide content corresponding to the passed CID, call this function to no + * longer remind them. + */ + cancelReprovide (key: CID, options?: RoutingOptions): Promise + + /** + * Find the providers of the passed CID. + * + * @example + * + * ```TypeScript + * // Iterate over the providers found for the given cid + * for await (const provider of contentRouting.findProviders(cid)) { + * console.log(provider.id, provider.multiaddrs) + * } + * ``` + */ + findProviders(cid: CID, options?: RoutingOptions): AsyncIterable + + /** + * Puts a value corresponding to the passed key in a way that can later be + * retrieved by another network peer using the get method. + * + * @example + * + * ```TypeScript + * // ... + * const key = '/key' + * const value = uint8ArrayFromString('oh hello there') + * + * await contentRouting.put(key, value) + * ``` + */ + put(key: Uint8Array, value: Uint8Array, options?: RoutingOptions): Promise + + /** + * Retrieves a value from the network corresponding to the passed key. + * + * @example + * + * ```TypeScript + * // ... + * + * const key = '/key' + * const value = await contentRouting.get(key) + * ``` + */ + get(key: Uint8Array, options?: RoutingOptions): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/errors.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/errors.ts new file mode 100644 index 000000000..aca3b6227 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/errors.ts @@ -0,0 +1,401 @@ +/** + * When this error is thrown it means an operation was aborted, + * usually in response to the `abort` event being emitted by an + * AbortSignal. + */ +export class AbortError extends Error { + static name = 'AbortError' + + constructor (message: string = 'The operation was aborted') { + super(message) + this.name = 'AbortError' + } +} + +/** + * Thrown when a remote Peer ID does not match the expected one + */ +export class UnexpectedPeerError extends Error { + static name = 'UnexpectedPeerError' + + constructor (message = 'Unexpected Peer') { + super(message) + this.name = 'UnexpectedPeerError' + } +} + +/** + * Thrown when a crypto exchange fails + */ +export class InvalidCryptoExchangeError extends Error { + static name = 'InvalidCryptoExchangeError' + + constructor (message = 'Invalid crypto exchange') { + super(message) + this.name = 'InvalidCryptoExchangeError' + } +} + +/** + * Thrown when invalid parameters are passed to a function or method call + */ +export class InvalidParametersError extends Error { + static name = 'InvalidParametersError' + + constructor (message = 'Invalid parameters') { + super(message) + this.name = 'InvalidParametersError' + } +} + +/** + * Thrown when a public key is invalid + */ +export class InvalidPublicKeyError extends Error { + static name = 'InvalidPublicKeyError' + + constructor (message = 'Invalid public key') { + super(message) + this.name = 'InvalidPublicKeyError' + } +} + +/** + * Thrown when a private key is invalid + */ +export class InvalidPrivateKeyError extends Error { + static name = 'InvalidPrivateKeyError' + + constructor (message = 'Invalid private key') { + super(message) + this.name = 'InvalidPrivateKeyError' + } +} + +/** + * Thrown when a operation is unsupported + */ +export class UnsupportedOperationError extends Error { + static name = 'UnsupportedOperationError' + + constructor (message = 'Unsupported operation') { + super(message) + this.name = 'UnsupportedOperationError' + } +} + +/** + * Thrown when a connection is closing + */ +export class ConnectionClosingError extends Error { + static name = 'ConnectionClosingError' + + constructor (message = 'The connection is closing') { + super(message) + this.name = 'ConnectionClosingError' + } +} + +/** + * Thrown when a connection is closed + */ +export class ConnectionClosedError extends Error { + static name = 'ConnectionClosedError' + + constructor (message = 'The connection is closed') { + super(message) + this.name = 'ConnectionClosedError' + } +} + +/** + * Thrown when a connection fails + */ +export class ConnectionFailedError extends Error { + static name = 'ConnectionFailedError' + + constructor (message = 'Connection failed') { + super(message) + this.name = 'ConnectionFailedError' + } +} + +/** + * Thrown when the muxer is closed and an attempt to open a stream occurs + */ +export class MuxerClosedError extends Error { + static name = 'MuxerClosedError' + + constructor (message = 'The muxer is closed') { + super(message) + this.name = 'MuxerClosedError' + } +} + +/** + * Thrown when a protocol stream is closed during an operation + */ +export class StreamClosedError extends Error { + static name = 'StreamClosedError' + + constructor (message = 'The stream has been closed') { + super(message) + this.name = 'StreamClosedError' + } +} + +/** + * Thrown when a protocol stream is reset by the remote muxer + */ +export class StreamResetError extends Error { + static name = 'StreamResetError' + + constructor (message = 'The stream has been reset') { + super(message) + this.name = 'StreamResetError' + } +} + +/** + * Thrown when a stream is in an invalid state + */ +export class StreamStateError extends Error { + static name = 'StreamStateError' + + constructor (message = 'The stream is in an invalid state') { + super(message) + this.name = 'StreamStateError' + } +} + +/** + * Thrown when a stream buffer is full + */ +export class StreamBufferError extends Error { + static name = 'StreamBufferError' + + constructor (message = 'The stream buffer was full') { + super(message) + this.name = 'StreamBufferError' + } +} + +/** + * Thrown when a value could not be found + */ +export class NotFoundError extends Error { + static name = 'NotFoundError' + + constructor (message = 'Not found') { + super(message) + this.name = 'NotFoundError' + } +} + +/** + * Thrown when an invalid peer ID is encountered + */ +export class InvalidPeerIdError extends Error { + static name = 'InvalidPeerIdError' + + constructor (message = 'Invalid PeerID') { + super(message) + this.name = 'InvalidPeerIdError' + } +} + +/** + * Thrown when an invalid multiaddr is encountered + */ +export class InvalidMultiaddrError extends Error { + static name = 'InvalidMultiaddrError' + + constructor (message = 'Invalid multiaddr') { + super(message) + this.name = 'InvalidMultiaddrError' + } +} + +/** + * Thrown when an invalid CID is encountered + */ +export class InvalidCIDError extends Error { + static name = 'InvalidCIDError' + + constructor (message = 'Invalid CID') { + super(message) + this.name = 'InvalidCIDError' + } +} + +/** + * Thrown when an invalid multihash is encountered + */ +export class InvalidMultihashError extends Error { + static name = 'InvalidMultihashError' + + constructor (message = 'Invalid Multihash') { + super(message) + this.name = 'InvalidMultihashError' + } +} + +/** + * Thrown when a protocol is not supported + */ +export class UnsupportedProtocolError extends Error { + static name = 'UnsupportedProtocolError' + + constructor (message = 'Unsupported protocol error') { + super(message) + this.name = 'UnsupportedProtocolError' + } +} + +/** + * An invalid or malformed message was encountered during a protocol exchange + */ +export class InvalidMessageError extends Error { + static name = 'InvalidMessageError' + + constructor (message = 'Invalid message') { + super(message) + this.name = 'InvalidMessageError' + } +} + +/** + * Thrown when a remote peer sends a structurally valid message that does not + * comply with the protocol + */ +export class ProtocolError extends Error { + static name = 'ProtocolError' + + constructor (message = 'Protocol error') { + super(message) + this.name = 'ProtocolError' + } +} + +/** + * Throw when an operation times out + */ +export class TimeoutError extends Error { + static name = 'TimeoutError' + + constructor (message = 'Timed out') { + super(message) + this.name = 'TimeoutError' + } +} + +/** + * Thrown when a startable component is interacted with but it has not been + * started yet + */ +export class NotStartedError extends Error { + static name = 'NotStartedError' + + constructor (message = 'Not started') { + super(message) + this.name = 'NotStartedError' + } +} + +/** + * Thrown when a component is started that has already been started + */ +export class AlreadyStartedError extends Error { + static name = 'AlreadyStartedError' + + constructor (message = 'Already started') { + super(message) + this.name = 'AlreadyStartedError' + } +} + +/** + * Thrown when dialing an address failed + */ +export class DialError extends Error { + static name = 'DialError' + + constructor (message = 'Dial error') { + super(message) + this.name = 'DialError' + } +} + +/** + * Thrown when listening on an address failed + */ +export class ListenError extends Error { + static name = 'ListenError' + + constructor (message = 'Listen error') { + super(message) + this.name = 'ListenError' + } +} + +/** + * This error is thrown when a limited connection is encountered, i.e. if the + * user tried to open a stream on a connection for a protocol that is not + * configured to run over limited connections. + */ +export class LimitedConnectionError extends Error { + static name = 'LimitedConnectionError' + + constructor (message = 'Limited connection') { + super(message) + this.name = 'LimitedConnectionError' + } +} + +/** + * This error is thrown where there are too many inbound protocols streams open + */ +export class TooManyInboundProtocolStreamsError extends Error { + static name = 'TooManyInboundProtocolStreamsError' + + constructor (message = 'Too many inbound protocol streams') { + super(message) + this.name = 'TooManyInboundProtocolStreamsError' + } +} + +/** + * This error is thrown where there are too many outbound protocols streams open + */ +export class TooManyOutboundProtocolStreamsError extends Error { + static name = 'TooManyOutboundProtocolStreamsError' + + constructor (message = 'Too many outbound protocol streams') { + super(message) + this.name = 'TooManyOutboundProtocolStreamsError' + } +} + +/** + * Thrown when an attempt to operate on an unsupported key was made + */ +export class UnsupportedKeyTypeError extends Error { + static name = 'UnsupportedKeyTypeError' + + constructor (message = 'Unsupported key type') { + super(message) + this.name = 'UnsupportedKeyTypeError' + } +} + +/** + * Thrown when an operation has not been implemented + */ +export class NotImplementedError extends Error { + static name = 'NotImplementedError' + + constructor (message = 'Not implemented') { + super(message) + this.name = 'NotImplementedError' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/events.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/events.ts new file mode 100644 index 000000000..9ffff8a6b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/events.ts @@ -0,0 +1,44 @@ +import type { Uint8ArrayList } from 'uint8arraylist' + +/** + * A custom implementation of MessageEvent as the Undici version does too much + * validation in it's constructor so is very slow. + */ +export class StreamMessageEvent extends Event { + public data: Uint8Array | Uint8ArrayList + + constructor (data: Uint8Array | Uint8ArrayList, eventInitDict?: EventInit) { + super('message', eventInitDict) + + this.data = data + } +} + +/** + * An event dispatched when the stream is closed. The `error` property can be + * inspected to discover if the closing was graceful or not, and the `remote` + * property shows which end of the stream initiated the closure + */ +export class StreamCloseEvent extends Event { + public error?: Error + public local?: boolean + + constructor (local?: boolean, error?: Error, eventInitDict?: EventInit) { + super('close', eventInitDict) + + this.error = error + this.local = local + } +} + +export class StreamAbortEvent extends StreamCloseEvent { + constructor (error: Error, eventInitDict?: EventInit) { + super(true, error, eventInitDict) + } +} + +export class StreamResetEvent extends StreamCloseEvent { + constructor (error: Error, eventInitDict?: EventInit) { + super(false, error, eventInitDict) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/index.ts new file mode 100644 index 000000000..33f21394c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/index.ts @@ -0,0 +1,941 @@ +/** + * @packageDocumentation + * + * Exports a `Libp2p` type for modules to use as a type argument. + * + * @example + * + * ```typescript + * import type { Libp2p } from '@libp2p/interface' + * + * function doSomethingWithLibp2p (node: Libp2p) { + * // ... + * } + * ``` + */ + +import type { Connection, NewStreamOptions } from './connection.js' +import type { ContentRouting } from './content-routing.js' +import type { Ed25519PublicKey, PublicKey, RSAPublicKey, Secp256k1PublicKey } from './keys.js' +import type { Metrics } from './metrics.js' +import type { Ed25519PeerId, PeerId, RSAPeerId, Secp256k1PeerId, URLPeerId } from './peer-id.js' +import type { PeerInfo } from './peer-info.js' +import type { PeerRouting } from './peer-routing.js' +import type { Address, Peer, PeerStore } from './peer-store.js' +import type { Startable } from './startable.js' +import type { StreamHandler, StreamHandlerOptions } from './stream-handler.js' +import type { Stream } from './stream.js' +import type { Topology } from './topology.js' +import type { Listener, OutboundConnectionUpgradeEvents } from './transport.js' +import type { DNS } from '@multiformats/dns' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { TypedEventTarget } from 'main-event' +import type { ProgressOptions, ProgressEvent } from 'progress-events' + +/** + * Used by the connection manager to sort addresses into order before dialling + */ +export interface AddressSorter { + (a: Address, b: Address): -1 | 0 | 1 +} + +/** + * Event detail emitted when peer data changes + */ +export interface PeerUpdate { + peer: Peer + previous?: Peer +} + +/** + * Peer data signed by the remote Peer's public key + */ +export interface SignedPeerRecord { + addresses: Multiaddr[] + seq: bigint +} + +/** + * A certificate that can be used to secure connections + */ +export interface TLSCertificate { + /** + * The private key that corresponds to the certificate in PEM format + */ + key: string + + /** + * The certificate chain in PEM format + */ + cert: string +} + +/** + * Data returned from a successful identify response + */ +export interface IdentifyResult { + /** + * The remote Peer's PeerId + */ + peerId: PeerId + + /** + * The unsigned addresses they are listening on. Note - any multiaddrs present + * in the signed peer record should be preferred to the value here. + */ + listenAddrs: Multiaddr[] + + /** + * The protocols the remote peer supports + */ + protocols: string[] + + /** + * The remote protocol version + */ + protocolVersion?: string + + /** + * The remote agent version + */ + agentVersion?: string + + /** + * The public key part of the remote PeerId - this is only useful for older + * RSA-based PeerIds, the more modern Ed25519 and secp256k1 types have the + * public key embedded in them + */ + publicKey?: Uint8Array + + /** + * If set this is the address that the remote peer saw the identify request + * originate from + */ + observedAddr?: Multiaddr + + /** + * If sent by the remote peer this is the deserialized signed peer record + */ + signedPeerRecord?: SignedPeerRecord + + /** + * The connection that the identify protocol ran over + */ + connection: Connection +} + +/** + * Logger component for libp2p + */ +export interface Logger { + /** + * Log a message + */ + (formatter: any, ...args: any[]): void + + /** + * Log an error message + */ + error(formatter: any, ...args: any[]): void + + /** + * Log a trace message + */ + trace(formatter: any, ...args: any[]): void + + /** + * `true` if this logger is enabled + */ + enabled: boolean + + /** + * Create a logger scoped below this one + * + * @example + * + * ```ts + * import { defaultLogger } from '@libp2p/logger' + * + * const log = defaultLogger().forComponent('foo') + * + * log('hello') + * // foo hello + * + * const subLog = log.newScope('bar') + * + * subLog('hello') + * // foo:bar hello + * ``` + */ + newScope(name: string): Logger +} + +/** + * Peer logger component for libp2p. This can be used to create loggers that are + * scoped to individual system components or services. + * + * To see logs, run your app with `DEBUG` set as an env var or for browsers, in + * `localStorage`: + * + * ```console + * $ DEBUG=libp2p* node index.js + * libp2p:my-service hello +0ms + * ``` + */ +export interface ComponentLogger { + /** + * Returns a logger for the specified component. + * + * @example + * + * ```TypeScript + * import { ComponentLogger, Logger } from '@libp2p/interface' + * + * interface MyServiceComponents { + * logger: ComponentLogger + * } + * + * class MyService { + * private readonly log: Logger + * + * constructor (components) { + * this.log = components.logger.forComponent('libp2p:my-service') + * + * this.log('hello') + * // logs: + * // libp2p:my-service hello +0ms + * } + * } + * ``` + */ + forComponent(name: string): Logger +} + +export interface MultiaddrResolveOptions extends AbortOptions, LoggerOptions { + /** + * An optional DNS resolver + */ + dns?: DNS +} + +/** + * `MultiaddrResolver`s perform resolution of multiaddr components that require + * translation by external systems (for example DNSADDR to TXT records). + */ +export interface MultiaddrResolver { + /** + * Returns true if this resolver can resolve components of this multiaddr + */ + canResolve (address: Multiaddr): boolean + + /** + * Returns one or more multiaddrs with components resolved to other values + */ + resolve (address: Multiaddr, options: MultiaddrResolveOptions): Promise +} + +/** + * Once you have a libp2p instance, you can listen to several events it emits, + * so that you can be notified of relevant network events. + * + * Event names are `noun:verb` so the first part is the name of the object + * being acted on and the second is the action. + */ +export interface Libp2pEvents { + /** + * This event is dispatched when a new network peer is discovered. + * + * @example + * + * ```TypeScript + * libp2p.addEventListener('peer:discovery', (event) => { + * const peerInfo = event.detail + * // ... + * }) + * ``` + */ + 'peer:discovery': CustomEvent + + /** + * This event will be triggered any time a new peer connects. + * + * @example + * + * ```TypeScript + * libp2p.addEventListener('peer:connect', (event) => { + * const peerId = event.detail + * // ... + * }) + * ``` + */ + 'peer:connect': CustomEvent + + /** + * This event will be triggered any time we are disconnected from another + * peer, regardless of the circumstances of that disconnection. If we happen + * to have multiple connections to a peer, this event will **only** be + * triggered when the last connection is closed. + * + * @example + * + * ```TypeScript + * libp2p.addEventListener('peer:disconnect', (event) => { + * const peerId = event.detail + * // ... + * }) + * ``` + */ + 'peer:disconnect': CustomEvent + + /** + * When a peer tagged with `keep-alive` disconnects, we will make multiple + * attempts to reconnect to it with a backoff factor (see the connection + * manager settings for details). If these all fail, the `keep-alive` tag will + * be removed and this event will be emitted. + * + * @example + * + * ```TypeScript + * libp2p.addEventListener('peer:reconnect-failure', (event) => { + * const peerId = event.detail + * // ... + * }) + * ``` + */ + 'peer:reconnect-failure': CustomEvent + + /** + * This event is dispatched after a remote peer has successfully responded to + * the identify protocol. Note that for this to be emitted, both peers must + * have an identify service configured. + * + * @example + * + * ```TypeScript + * libp2p.addEventListener('peer:identify', (event) => { + * const identifyResult = event.detail + * // ... + * }) + * ``` + */ + 'peer:identify': CustomEvent + + /** + * This event is dispatched when the peer store data for a peer has been + * updated - e.g. their multiaddrs, protocols etc have changed. + * + * If they were previously known to this node, the old peer data will be + * set in the `previous` field. + * + * This may be in response to the identify protocol running, a manual + * update or some other event. + */ + 'peer:update': CustomEvent + + /** + * This event is dispatched when the current node's peer record changes - + * for example a transport started listening on a new address or a new + * protocol handler was registered. + * + * @example + * + * ```TypeScript + * libp2p.addEventListener('self:peer:update', (event) => { + * const { peer } = event.detail + * // ... + * }) + * ``` + */ + 'self:peer:update': CustomEvent + + /** + * This event is dispatched when a transport begins listening on a new address + */ + 'transport:listening': CustomEvent + + /** + * This event is dispatched when a transport stops listening on an address + */ + 'transport:close': CustomEvent + + /** + * This event is dispatched when the connection manager has more than the + * configured allowable max connections and has closed some connections to + * bring the node back under the limit. + */ + 'connection:prune': CustomEvent + + /** + * This event notifies listeners when new incoming or outgoing connections + * are opened. + */ + 'connection:open': CustomEvent + + /** + * This event notifies listeners when incoming or outgoing connections are + * closed. + */ + 'connection:close': CustomEvent + + /** + * This event notifies listeners that a TLS certificate is available for use + */ + 'certificate:provision': CustomEvent + + /** + * This event notifies listeners that a new TLS certificate is available for + * use. Any previous certificate may no longer be valid. + */ + 'certificate:renew': CustomEvent + + /** + * This event notifies listeners that the node has started + * + * ```TypeScript + * libp2p.addEventListener('start', (event) => { + * console.info(libp2p.isStarted()) // true + * }) + * ``` + */ + start: CustomEvent> + + /** + * This event notifies listeners that the node has stopped + * + * ```TypeScript + * libp2p.addEventListener('stop', (event) => { + * console.info(libp2p.isStarted()) // false + * }) + * ``` + */ + stop: CustomEvent> +} + +/** + * A map of user defined services available on the libp2p node via the + * `services` key + * + * @example + * + * ```TypeScript + * const node = await createLibp2p({ + * // ...other options + * services: { + * myService: myService({ + * // ...service options + * }) + * } + * }) + * + * // invoke methods on the service + * node.services.myService.anOperation() + * ``` + */ +export type ServiceMap = Record + +export type PendingDialStatus = 'queued' | 'active' | 'error' | 'success' + +/** + * An item in the dial queue + */ +export interface PendingDial { + /** + * A unique identifier for this dial + */ + id: string + + /** + * The current status of the dial + */ + status: PendingDialStatus + + /** + * If known, this is the peer id that libp2p expects to be dialling + */ + peerId?: PeerId + + /** + * The list of multiaddrs that will be dialled. The returned connection will + * use the first address that succeeds, all other dials part of this pending + * dial will be cancelled. + */ + multiaddrs: Multiaddr[] +} + +export type Libp2pStatus = 'starting' | 'started' | 'stopping' | 'stopped' + +export interface IsDialableOptions extends AbortOptions { + /** + * If the dial attempt would open a protocol, and the multiaddr being dialed + * is a circuit relay address, passing true here would cause the test to fail + * because that protocol would not be allowed to run over a data/time limited + * connection. + */ + runOnLimitedConnection?: boolean +} + +export type TransportManagerDialProgressEvents = + ProgressEvent<'transport-manager:selected-transport', string> + +export type OpenConnectionProgressEvents = + TransportManagerDialProgressEvents | + ProgressEvent<'dial-queue:already-connected'> | + ProgressEvent<'dial-queue:already-in-dial-queue'> | + ProgressEvent<'dial-queue:add-to-dial-queue'> | + ProgressEvent<'dial-queue:start-dial'> | + ProgressEvent<'dial-queue:calculated-addresses', Address[]> | + OutboundConnectionUpgradeEvents + +export interface DialOptions extends AbortOptions, ProgressOptions { + /** + * If true, open a new connection to the remote even if one already exists + */ + force?: boolean +} + +export interface DialProtocolOptions extends NewStreamOptions { + +} + +/** + * Libp2p nodes implement this interface. + */ +export interface Libp2p extends Startable, TypedEventTarget> { + /** + * The PeerId is a unique identifier for a node on the network. + * + * It is the hash of an RSA public key or, for Ed25519 or secp256k1 keys, + * the key itself. + * + * @example + * + * ```TypeScript + * console.info(libp2p.peerId) + * // PeerId(12D3Foo...) + * ```` + */ + peerId: PeerId + + /** + * The peer store holds information we know about other peers on the network. + * - multiaddrs, supported protocols, etc. + * + * @example + * + * ```TypeScript + * const peer = await libp2p.peerStore.get(peerId) + * console.info(peer) + * // { id: PeerId(12D3Foo...), addresses: [] ... } + * ``` + */ + peerStore: PeerStore + + /** + * The peer routing subsystem allows the user to find peers on the network + * or to find peers close to binary keys. + * + * @example + * + * ```TypeScript + * const peerInfo = await libp2p.peerRouting.findPeer(peerId) + * console.info(peerInfo) + * // { id: PeerId(12D3Foo...), multiaddrs: [] ... } + * ``` + * + * @example + * + * ```TypeScript + * for await (const peerInfo of libp2p.peerRouting.getClosestPeers(key)) { + * console.info(peerInfo) + * // { id: PeerId(12D3Foo...), multiaddrs: [] ... } + * } + * ``` + */ + peerRouting: PeerRouting + + /** + * The content routing subsystem allows the user to find providers for content, + * let the network know they are providers for content, and get/put values to + * the DHT. + * + * @example + * + * ```TypeScript + * for await (const peerInfo of libp2p.contentRouting.findProviders(cid)) { + * console.info(peerInfo) + * // { id: PeerId(12D3Foo...), multiaddrs: [] ... } + * } + * ``` + */ + contentRouting: ContentRouting + + /** + * The metrics subsystem allows recording values to assess the health/performance + * of the running node. + * + * @example + * + * ```TypeScript + * const metric = libp2p.metrics.registerMetric({ + * 'my-metric' + * }) + * + * // later + * metric.update(5) + * ``` + */ + metrics?: Metrics + + /** + * The logger used by this libp2p node + */ + logger: ComponentLogger + + /** + * The current status of the libp2p node + */ + status: Libp2pStatus + + /** + * Get a deduplicated list of peer advertising multiaddrs by concatenating + * the listen addresses used by transports with any configured + * announce addresses as well as observed addresses reported by peers. + * + * If Announce addrs are specified, configured listen addresses will be + * ignored though observed addresses will still be included. + * + * @example + * + * ```TypeScript + * const listenMa = libp2p.getMultiaddrs() + * // [ ] + * ``` + */ + getMultiaddrs(): Multiaddr[] + + /** + * Returns a list of supported protocols + * + * @example + * + * ```TypeScript + * const protocols = libp2p.getProtocols() + * // [ '/ipfs/ping/1.0.0', '/ipfs/id/1.0.0' ] + * ``` + */ + getProtocols(): string[] + + /** + * Return a list of all connections this node has open, optionally filtering + * by a PeerId + * + * @example + * + * ```TypeScript + * for (const connection of libp2p.getConnections()) { + * console.log(peerId, connection.remoteAddr.toString()) + * // Logs the PeerId string and the observed remote multiaddr of each Connection + * } + * ``` + */ + getConnections(peerId?: PeerId): Connection[] + + /** + * Return the list of dials currently in progress or queued to start + * + * @example + * + * ```TypeScript + * for (const pendingDial of libp2p.getDialQueue()) { + * console.log(pendingDial) + * } + * ``` + */ + getDialQueue(): PendingDial[] + + /** + * Return a list of all peers we currently have a connection open to + */ + getPeers(): PeerId[] + + /** + * Dials to the provided peer. If successful, the known metadata of the + * peer will be added to the nodes `peerStore`. + * + * If a PeerId is passed as the first argument, the peer will need to have known multiaddrs for it in the PeerStore. + * + * @example + * + * ```TypeScript + * const conn = await libp2p.dial(remotePeerId) + * + * // create a new stream within the connection + * const stream = await conn.newStream(['/echo/1.1.0', '/echo/1.0.0']) + * + * // protocol negotiated: 'echo/1.0.0' means that the other party only supports the older version + * + * // ... + * await conn.close() + * ``` + */ + dial(peer: PeerId | Multiaddr | Multiaddr[], options?: DialOptions): Promise + + /** + * Dials to the provided peer and tries to handshake with the given protocols in order. + * If successful, the known metadata of the peer will be added to the nodes `peerStore`, + * and the `MuxedStream` will be returned together with the successful negotiated protocol. + * + * @example + * + * ```TypeScript + * import { pipe } from 'it-pipe' + * + * const { stream, protocol } = await libp2p.dialProtocol(remotePeerId, protocols) + * + * // Use this new stream like any other duplex stream + * pipe([1, 2, 3], stream, consume) + * ``` + */ + dialProtocol(peer: PeerId | Multiaddr | Multiaddr[], protocols: string | string[], options?: DialProtocolOptions): Promise + + /** + * Attempts to gracefully close an open connection to the given peer. If the + * connection is not closed in the grace period, it will be forcefully closed. + * + * An AbortSignal can optionally be passed to control when the connection is + * forcefully closed. + * + * @example + * + * ```TypeScript + * await libp2p.hangUp(remotePeerId) + * ``` + */ + hangUp(peer: PeerId | Multiaddr, options?: AbortOptions): Promise + + /** + * Sets up [multistream-select routing](https://github.com/multiformats/multistream-select) of protocols to their application handlers. Whenever a stream is opened on one of the provided protocols, the handler will be called. `handle` must be called in order to register a handler and support for a given protocol. This also informs other peers of the protocols you support. + * + * `libp2p.handle(protocols, handler, options)` + * + * In the event of a new handler for the same protocol being added and error + * will be thrown. Pass `force: true` to override this. + * + * @example + * + * ```TypeScript + * const handler = ({ connection, stream, protocol }) => { + * // use stream or connection according to the needs + * } + * + * libp2p.handle('/echo/1.0.0', handler, { + * maxInboundStreams: 5, + * maxOutboundStreams: 5 + * }) + * ``` + */ + handle(protocol: string | string[], handler: StreamHandler, options?: StreamHandlerOptions): Promise + + /** + * Removes the handler for each protocol. The protocol + * will no longer be supported on streams. + * + * @example + * + * ```TypeScript + * libp2p.unhandle(['/echo/1.0.0']) + * ``` + */ + unhandle(protocols: string[] | string, options?: AbortOptions): Promise + + /** + * Register a topology to be informed when peers are encountered that + * support the specified protocol + * + * @example + * + * ```TypeScript + * const id = await libp2p.register('/echo/1.0.0', { + * onConnect: (peer, connection) => { + * // handle connect + * }, + * onDisconnect: (peer, connection) => { + * // handle disconnect + * } + * }) + * ``` + */ + register(protocol: string, topology: Topology, options?: AbortOptions): Promise + + /** + * Unregister topology to no longer be informed when peers connect or + * disconnect. + * + * @example + * + * ```TypeScript + * const id = await libp2p.register(...) + * + * libp2p.unregister(id) + * ``` + */ + unregister(id: string): void + + /** + * Returns the public key for the passed PeerId. If the PeerId is of the 'RSA' + * type this may mean searching the routing if the peer's key is not present + * in the peer store. + */ + getPublicKey(peer: Ed25519PeerId, options?: AbortOptions): Promise + getPublicKey(peer: Secp256k1PeerId, options?: AbortOptions): Promise + getPublicKey(peer: RSAPeerId, options?: AbortOptions): Promise + getPublicKey(peer: URLPeerId, options?: AbortOptions): Promise + getPublicKey(peer: PeerId, options?: AbortOptions): Promise + + /** + * Given the current node configuration, returns a promise of `true` or + * `false` if the node would attempt to dial the passed multiaddr. + * + * This means a relevant transport is configured, and the connection gater + * would not block the dial attempt. + * + * This may involve resolving DNS addresses so you should pass an AbortSignal. + */ + isDialable(multiaddr: Multiaddr | Multiaddr[], options?: IsDialableOptions): Promise + + /** + * A set of user defined services + */ + services: T +} + +/** + * Metadata about the current node + */ +export interface NodeInfo { + /** + * The implementation name + */ + name: string + + /** + * The implementation version + */ + version: string + + /** + * A string that contains information about the implementation and runtime + */ + userAgent: string +} + +/** + * An object that contains an AbortSignal as + * the optional `signal` property. + * + * @example + * + * ```TypeScript + * const controller = new AbortController() + * + * aLongRunningOperation({ + * signal: controller.signal + * }) + * + * // later + * + * controller.abort() + */ +export interface AbortOptions { + signal?: AbortSignal +} + +/** + * An object that contains a Logger as the `log` property. + */ +export interface LoggerOptions { + log: Logger +} + +/** + * An object that includes a trace object that is passed onwards. + * + * This is used by metrics method tracing to link function calls together. + */ +export interface TraceOptions { + trace?: any +} + +/** + * A signal that needs to be cleared when no longer in use + */ +export interface ClearableSignal extends AbortSignal { + clear(): void +} + +/** + * When a routing operation involves reading values, these options allow + * controlling where the values are read from. By default libp2p will check + * local caches but may not use the network if a valid local value is found, + * these options allow tuning that behavior. + */ +export interface RoutingOptions extends AbortOptions, ProgressOptions, TraceOptions { + /** + * Pass `false` to not use the network + * + * @default true + */ + useNetwork?: boolean + + /** + * Pass `false` to not use cached values + * + * @default true + */ + useCache?: boolean +} + +/** + * This symbol is used by libp2p services to define the capabilities they can + * provide to other libp2p services. + * + * The service should define a property with this symbol as the key and the + * value should be a string array of provided capabilities. + */ +export const serviceCapabilities = Symbol.for('@libp2p/service-capabilities') + +/** + * This symbol is used by libp2p services to define the capabilities they + * require from other libp2p services. + * + * The service should define a property with this symbol as the key and the + * value should be a string array of required capabilities. + */ +export const serviceDependencies = Symbol.for('@libp2p/service-dependencies') + +export * from './connection.js' +export * from './connection-encrypter.js' +export * from './connection-gater.js' +export * from './connection-protector.js' +export * from './content-routing.js' +export * from './errors.js' +export * from './events.js' +export * from './keys.js' +export * from './message-stream.js' +export * from './metrics.js' +export * from './multiaddr-connection.js' +export * from './peer-discovery.js' +export * from './peer-id.js' +export * from './peer-info.js' +export * from './peer-routing.js' +export * from './peer-store.js' +export * from './pubsub.js' +export * from './record.js' +export * from './startable.js' +export * from './stream-handler.js' +export * from './stream-muxer.js' +export * from './stream.js' +export * from './topology.js' +export * from './transport.js' + +export * from 'main-event' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/keys.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/keys.ts new file mode 100644 index 000000000..1967529f5 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/keys.ts @@ -0,0 +1,347 @@ +import type { AbortOptions } from './index.ts' +import type { CID } from 'multiformats/cid' +import type { MultihashDigest } from 'multiformats/hashes/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +export type KeyType = 'RSA' | 'Ed25519' | 'secp256k1' | 'ECDSA' + +export interface RSAPublicKey { + /** + * The type of this key + */ + readonly type: 'RSA' + + /** + * PKIX in ASN1 DER format + */ + readonly raw: Uint8Array + + /** + * The public key as a JSON web key + */ + readonly jwk: JsonWebKey + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Returns this public key as a Multihash digest. + * + * It contains a sha256 hash of the protobuf version of the public key. + */ + toMultihash(): MultihashDigest<0x12> + + /** + * Return this public key as a CID encoded with the `libp2p-key` codec + * + * The digest contains a sha256 hash of the protobuf version of the public + * key. + */ + toCID(): CID + + /** + * Verify the passed data was signed by the private key corresponding to this + * public key + */ + verify(data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): boolean | Promise + + /** + * Returns this key as a multihash with base58btc encoding + */ + toString(): string +} + +export interface Ed25519PublicKey { + /** + * The type of this key + */ + readonly type: 'Ed25519' + + /** + * The raw public key bytes + */ + readonly raw: Uint8Array + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Returns this public key as an identity hash containing the protobuf wrapped + * public key + */ + toMultihash(): MultihashDigest<0x0> + + /** + * Return this public key as a CID encoded with the `libp2p-key` codec + * + * The digest contains an identity hash containing the protobuf wrapped + * version of the public key. + */ + toCID(): CID + + /** + * Verify the passed data was signed by the private key corresponding to this + * public key + */ + verify(data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): boolean | Promise + + /** + * Returns this key as a multihash with base58btc encoding + */ + toString(): string +} + +export interface Secp256k1PublicKey { + /** + * The type of this key + */ + readonly type: 'secp256k1' + + /** + * The raw public key bytes + */ + readonly raw: Uint8Array + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Returns this public key as an identity hash containing the protobuf wrapped + * public key + */ + toMultihash(): MultihashDigest<0x0> + + /** + * Return this public key as a CID encoded with the `libp2p-key` codec + * + * The digest contains an identity hash containing the protobuf wrapped + * version of the public key. + */ + toCID(): CID + + /** + * Verify the passed data was signed by the private key corresponding to this + * public key + */ + verify(data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): boolean | Promise + + /** + * Returns this key as a multihash with base58btc encoding + */ + toString(): string +} + +export interface ECDSAPublicKey { + /** + * The type of this key + */ + readonly type: 'ECDSA' + + /** + * The public key as a DER-encoded PKIMessage + */ + readonly raw: Uint8Array + + /** + * The public key as a JSON web key + */ + readonly jwk: JsonWebKey + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Returns this public key as an identity hash containing the protobuf wrapped + * public key + */ + toMultihash(): MultihashDigest<0x0> + + /** + * Return this public key as a CID encoded with the `libp2p-key` codec + * + * The digest contains an identity hash containing the protobuf wrapped + * version of the public key. + */ + toCID(): CID + + /** + * Verify the passed data was signed by the private key corresponding to this + * public key + */ + verify(data: Uint8Array | Uint8ArrayList, sig: Uint8Array, options?: AbortOptions): boolean | Promise + + /** + * Returns this key as a multihash with base58btc encoding + */ + toString(): string +} + +export type PublicKey = RSAPublicKey | Ed25519PublicKey | Secp256k1PublicKey | ECDSAPublicKey + +/** + * Returns true if the passed argument has type overlap with the `PublicKey` + * interface. Can be used to disambiguate object types. + */ +export function isPublicKey (key?: any): key is PublicKey { + if (key == null) { + return false + } + + return (key.type === 'RSA' || key.type === 'Ed25519' || key.type === 'secp256k1' || key.type === 'ECDSA') && + key.raw instanceof Uint8Array && + typeof key.equals === 'function' && + typeof key.toMultihash === 'function' && + typeof key.toCID === 'function' && + typeof key.verify === 'function' +} + +/** + * Generic private key interface + */ +export interface RSAPrivateKey { + /** + * The type of this key + */ + readonly type: 'RSA' + + /** + * The public key that corresponds to this private key + */ + readonly publicKey: RSAPublicKey + + /** + * PKIX in ASN1 DER format + */ + readonly raw: Uint8Array + + /** + * The private key as a JSON web key + */ + readonly jwk: JsonWebKey + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Sign the passed data with this private key and return the signature for + * later verification + */ + sign(data: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise +} + +export interface Ed25519PrivateKey { + /** + * The type of this key + */ + readonly type: 'Ed25519' + + /** + * The public key that corresponds to this private key + */ + readonly publicKey: Ed25519PublicKey + + /** + * The raw private key bytes + */ + readonly raw: Uint8Array + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Sign the passed data with this private key and return the signature for + * later verification + */ + sign(data: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise +} + +export interface Secp256k1PrivateKey { + /** + * The type of this key + */ + readonly type: 'secp256k1' + + /** + * The public key that corresponds to this private key + */ + readonly publicKey: Secp256k1PublicKey + + /** + * The raw private key bytes + */ + readonly raw: Uint8Array + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Sign the passed data with this private key and return the signature for + * later verification + */ + sign(data: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise +} + +export interface ECDSAPrivateKey { + /** + * The type of this key + */ + readonly type: 'ECDSA' + + /** + * The public key that corresponds to this private key + */ + readonly publicKey: ECDSAPublicKey + + /** + * The private key as a DER-encoded PKIMessage + */ + readonly raw: Uint8Array + + /** + * The private key as a JSON web key + */ + readonly jwk: JsonWebKey + + /** + * Returns `true` if the passed object matches this key + */ + equals(key?: any): boolean + + /** + * Sign the passed data with this private key and return the signature for + * later verification + */ + sign(data: Uint8Array | Uint8ArrayList, options?: AbortOptions): Uint8Array | Promise +} + +export type PrivateKey = RSAPrivateKey | Ed25519PrivateKey | Secp256k1PrivateKey | ECDSAPrivateKey + +/** + * Returns true if the passed argument has type overlap with the `PrivateKey` + * interface. Can be used to disambiguate object types. + */ +export function isPrivateKey (key?: any): key is PrivateKey { + if (key == null) { + return false + } + + return (key.type === 'RSA' || key.type === 'Ed25519' || key.type === 'secp256k1' || key.type === 'ECDSA') && + isPublicKey(key.publicKey) && + key.raw instanceof Uint8Array && + typeof key.equals === 'function' && + typeof key.sign === 'function' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/message-stream.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/message-stream.ts new file mode 100644 index 000000000..4af5cd56e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/message-stream.ts @@ -0,0 +1,241 @@ +import type { Logger, StreamCloseEvent, StreamMessageEvent, TypedEventTarget } from './index.js' +import type { AbortOptions } from '@multiformats/multiaddr' +import type { Uint8ArrayList } from 'uint8arraylist' + +/** + * The direction of the message stream + */ +export type MessageStreamDirection = 'inbound' | 'outbound' + +/** + * The states a message stream can be in + */ +export type MessageStreamStatus = 'open' | 'closing' | 'closed' | 'aborted' | 'reset' + +/** + * The states the readable end of a message stream can be in + */ +export type MessageStreamReadStatus = 'readable' | 'paused' | 'closing' | 'closed' + +/** + * The states the writable end of a message stream can be in + */ +export type MessageStreamWriteStatus = 'writable' | 'paused' | 'closing' | 'closed' + +/** + * An object that records the times of various events + */ +export interface MessageStreamTimeline { + /** + * A timestamp of when the message stream was opened + */ + open: number + + /** + * A timestamp of when the message stream was closed for both reading and + * writing by both ends of the stream + */ + close?: number + + /** + * A timestamp of when the message stream was reset + */ + reset?: number + + /** + * A timestamp of when the message stream was aborted + */ + abort?: number + + /** + * A timestamp of when the stream was closed for reading + */ + closeRead?: number + + /** + * A timestamp of when the stream was closed for writing + */ + closeWrite?: number + + /** + * A timestamp of when the remote stream was closed for reading + */ + remoteCloseRead?: number + + /** + * A timestamp of when the remote stream was closed for writing + */ + remoteCloseWrite?: number +} + +export interface MessageStreamEvents { + /** + * Data was received from the remote end of the message stream + */ + message: StreamMessageEvent + + /** + * The local send buffer can now accept new data + */ + drain: Event + + /** + * Both ends of the closed their writable ends. + * + * The `local` property of the `StreamCloseEvent` can be used to detect + * whether the close event was initiated locally or remotely, and the `error` + * property can be used to tell if the stream closed gracefully or not. + * + * No further events will be emitted and the stream cannot be used to send or + * receive any more data. + */ + close: StreamCloseEvent + + /** + * The readable end of the stream closed gracefully + */ + closeRead: Event + + /** + * The writable end of the stream closed gracefully + */ + closeWrite: Event + + /** + * The remote closed it's readable end of the stream + */ + remoteCloseRead: Event + + /** + * The remote closed it's writable end of the stream + */ + remoteCloseWrite: Event +} + +export interface MessageStream extends TypedEventTarget, AsyncIterable { + /** + * Timestamps of when stream events occurred + */ + timeline: MessageStreamTimeline + + /** + * A logging implementation that can be used to log stream-specific messages + */ + log: Logger + + /** + * Whether this stream is inbound or outbound + */ + direction: MessageStreamDirection + + /** + * The current status of the message stream + */ + status: MessageStreamStatus + + /** + * The current status of the readable end of the stream + */ + readStatus: MessageStreamReadStatus + + /** + * The current status of the writable end of the stream + */ + writeStatus: MessageStreamWriteStatus + + /** + * The current status of the readable end of the stream + */ + remoteReadStatus: MessageStreamReadStatus + + /** + * The current status of the writable end of the stream + */ + remoteWriteStatus: MessageStreamWriteStatus + + /** + * The maximum number of bytes to store when paused. If receipt of more bytes + * from the remote end of the stream causes the buffer size to exceed this + * value the stream will be reset and an 'error' event emitted. + */ + maxPauseBufferLength: number + + /** + * If no data is transmitted over the stream in this many ms, the stream will + * be aborted with an InactivityTimeoutError + */ + inactivityTimeout: number + + /** + * Write data to the stream. If the method returns false it means the + * internal buffer is now full and the caller should wait for the 'drain' + * event before sending more data. + * + * This method may throw if: + * - The internal send buffer is full + * - The stream has previously been closed for writing locally or remotely + */ + send (data: Uint8Array | Uint8ArrayList): boolean + + /** + * Immediately close the stream for reading and writing, discard any + * unsent/unread data, and emit a StreamAbortEvent event. + */ + abort (err: Error): void + + /** + * Gracefully close the stream for reading and writing - any further calls to + * `.send` will throw. + * + * The returned promise will resolve when any outstanding data has been + * written out into the underlying resource. + * + * A 'close' event will be emitted on the stream once any buffered data has + * been sent and the remote end has also closed for writing. + * + * To close the stream immediately call `.abort` instead. + close (options?: AbortOptions): Promise + */ + + /** + * Sends a message to the remote informing them we will not read any more data + * from the stream. + * + * If the writable end of the stream is already closed, a 'close' event will + * be emitted on the stream. + */ + closeRead (options?: AbortOptions): Promise + + /** + * Gracefully close the stream for writing - any outstanding data will be sent + * to the remote and any further calls to `.send` will throw. + * + * If the readable end of the stream is already closed, a 'close' event will + * be emitted on the stream once any buffered data has been sent. + */ + closeWrite (options?: AbortOptions): Promise + + /** + * Stop emitting further 'message' events. Any received data will be stored in + * an internal buffer. If the buffer size reaches `maxPauseBufferLength`, the + * stream will be reset and a StreamAbortEvent emitted. + * + * If the underlying resource supports it, the remote peer will be instructed + * to pause transmission of further data. + */ + pause (): void + + /** + * Resume emitting 'message' events. + * + * If the underlying resource supports it, the remote peer will be informed + * that it is ok to start sending data again. + */ + resume (): void + + /** + * Queue the passed data to be emitted as a 'message' event either during the + * next tick or sooner if data is received from the underlying resource. + */ + push (buf: Uint8Array | Uint8ArrayList): void +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/metrics.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/metrics.ts new file mode 100644 index 000000000..c277843a7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/metrics.ts @@ -0,0 +1,548 @@ +import type { MultiaddrConnection, Stream } from './index.js' + +/** + * Create tracked metrics with these options. Loosely based on the + * interfaces exposed by the prom-client module + */ +export interface MetricOptions { + /** + * Optional label for the metric + */ + label?: string + + /** + * Optional help for the metric + */ + help?: string +} + +/** + * A function that returns a tracked metric which may be expensive + * to calculate so it is only invoked when metrics are being scraped + */ +export type CalculateMetric = (() => T) | (() => Promise) + +/** + * Create tracked metrics that are expensive to calculate by passing + * a function that is only invoked when metrics are being scraped + */ +export interface CalculatedMetricOptions extends MetricOptions { + /** + * An optional function invoked to calculate the component metric instead of + * using `.update`, `.increment`, and `.decrement` + */ + calculate: CalculateMetric +} + +/** + * Call this function to stop the timer returned from the `.timer` method + * on the metric + */ +export interface StopTimer { (): void } + +/** + * A tracked metric loosely based on the interfaces exposed by the + * prom-client module + */ +export interface Metric { + /** + * Update the stored metric to the passed value + */ + update(value: number): void + + /** + * Increment the metric by the passed value or 1 + */ + increment(value?: number): void + + /** + * Decrement the metric by the passed value or 1 + */ + decrement(value?: number): void + + /** + * Reset this metric to its default value + */ + reset(): void + + /** + * Start a timed metric, call the returned function to + * stop the timer + */ + timer(): StopTimer +} + +/** + * A group of related metrics loosely based on the interfaces exposed by the + * prom-client module + */ +export interface MetricGroup { + /** + * Update the stored metric group to the passed value + */ + update(values: Partial>): void + + /** + * Increment the metric group keys by the passed number or + * `true` to increment by 1 + */ + increment(values: Partial>): void + + /** + * Decrement the metric group keys by the passed number or + * `true` to decrement by 1 + */ + decrement(values: Partial>): void + + /** + * Reset the passed key in this metric group to its default value + * or all keys if no key is passed + */ + reset(): void + + /** + * Start a timed metric for the named key in the group, call + * the returned function to stop the timer + */ + timer(key: string): StopTimer +} + +/** + * A tracked counter loosely based on the Counter interface exposed + * by the prom-client module - counters are metrics that only go up + */ +export interface Counter { + /** + * Increment the metric by the passed value or 1 + */ + increment(value?: number): void + + /** + * Reset this metric to its default value + */ + reset(): void +} + +/** + * A group of tracked counters loosely based on the Counter interface + * exposed by the prom-client module - counters are metrics that only + * go up + */ +export interface CounterGroup { + /** + * Increment the metric group keys by the passed number or + * any non-numeric value to increment by 1 + */ + increment(values: Partial>): void + + /** + * Reset the passed key in this metric group to its default value + * or all keys if no key is passed + */ + reset(): void +} + +export interface HistogramOptions extends MetricOptions { + /** + * Buckets for the histogram + */ + buckets?: number[] +} + +/** + * Create tracked metrics that are expensive to calculate by passing + * a function that is only invoked when metrics are being scraped + */ +export interface CalculatedHistogramOptions extends HistogramOptions { + /** + * An optional function invoked to calculate the component metric instead of + * using `.observe` + */ + calculate: CalculateMetric +} + +export interface Histogram { + /** + * Observe the passed value + */ + observe(value: number): void + + /** + * Reset this histogram to its default value + */ + reset(): void + + /** + * Start a timed metric, call the returned function to + * stop the timer + */ + timer(): StopTimer +} + +export interface HistogramGroup { + /** + * Observe the passed value for the named key in the group + */ + observe(values: Partial>): void + + /** + * Reset the passed key in this histogram group to its default value + * or all keys if no key is passed + */ + reset(): void + + /** + * Start a timed metric for the named key in the group, call + * the returned function to stop the timer + */ + timer(key: string): StopTimer +} + +export interface SummaryOptions extends MetricOptions { + /** + * Percentiles for the summary + */ + percentiles?: number[] + + /** + * Configure how old a bucket can be before it is reset for sliding window + */ + maxAgeSeconds?: number + + /** + * Configure how many buckets in the sliding window + */ + ageBuckets?: number + + /** + * Remove entries without any new values in the last `maxAgeSeconds` + */ + pruneAgedBuckets?: boolean + + /** + * Control compression of data in t-digest + */ + compressCount?: number +} + +/** + * Create tracked metrics that are expensive to calculate by passing + * a function that is only invoked when metrics are being scraped + */ +export interface CalculatedSummaryOptions extends SummaryOptions { + /** + * An optional function invoked to calculate the component metric instead of + * using `.observe` + */ + calculate: CalculateMetric +} + +/** + * A tracked summary loosely based on the Summary interface exposed + * by the prom-client module + */ +export interface Summary { + /** + * Observe the passed value + */ + observe(value: number): void + + /** + * Reset this summary to its default value + */ + reset(): void + + /** + * Start a timed metric, call the returned function to + * stop the timer + */ + timer(): StopTimer +} + +/** + * A group of tracked summaries loosely based on the Summary interface + * exposed by the prom-client module + */ +export interface SummaryGroup { + /** + * Observe the passed value for the named key in the group + */ + observe(values: Partial>): void + + /** + * Reset the passed key in this summary group to its default value + * or all keys if no key is passed + */ + reset(): void + + /** + * Start a timed metric for the named key in the group, call + * the returned function to stop the timer + */ + timer(key: string): StopTimer +} + +/** + * The libp2p metrics tracking object. This interface is only concerned + * with the collection of metrics, please see the individual implementations + * for how to extract metrics for viewing. + * + * @example How to register a simple metric + * + * ```typescript + * import { Metrics, Metric } from '@libp2p/interface/metrics' + * + * interface MyServiceComponents { + * metrics: Metrics + * } + * + * class MyService { + * private readonly myMetric: Metric + * + * constructor (components: MyServiceComponents) { + * this.myMetric = components.metrics.registerMetric({ + * name: 'my_metric', + * label: 'my_label', + * help: 'my help text' + * }) + * } + * + * // later + * doSomething () { + * this.myMetric.update(1) + * } + * } + * ``` + * + * @example How to register a dynamically calculated metric + * + * A metric that is expensive to calculate can be created by passing a `calculate` function that will only be invoked when metrics are being scraped: + * + * ```typescript + * import { Metrics, Metric } from '@libp2p/interface/metrics' + * + * interface MyServiceComponents { + * metrics: Metrics + * } + * + * class MyService { + * private readonly myMetric: Metric + * + * constructor (components: MyServiceComponents) { + * this.myMetric = components.metrics.registerMetric({ + * name: 'my_metric', + * label: 'my_label', + * help: 'my help text', + * calculate: async () => { + * // do something expensive + * return 1 + * } + * }) + * } + * } + * ``` + * + * @example How to register a group of metrics + * + * If several metrics should be grouped together (e.g. for graphing purposes) `registerMetricGroup` can be used instead: + * + * ```typescript + * import { Metrics, MetricGroup } from '@libp2p/interface/metrics' + * + * interface MyServiceComponents { + * metrics: Metrics + * } + * + * class MyService { + * private readonly myMetricGroup: MetricGroup + * + * constructor (components: MyServiceComponents) { + * this.myMetricGroup = components.metrics.registerMetricGroup({ + * name: 'my_metric_group', + * label: 'my_label', + * help: 'my help text' + * }) + * } + * + * // later + * doSomething () { + * this.myMetricGroup.increment({ my_label: 'my_value' }) + * } + * } + * ``` + * + * There are specific metric groups for tracking libp2p connections and streams: + * + * @example How to track multiaddr connections + * + * This is something only libp2p transports need to do. + * + * ```typescript + * import { Metrics } from '@libp2p/interface/metrics' + * + * interface MyServiceComponents { + * metrics: Metrics + * } + * + * class MyService { + * private readonly metrics: Metrics + * + * constructor (components: MyServiceComponents) { + * this.metrics = components.metrics + * } + * + * // later + * doSomething () { + * const connection = {} // create a connection + * this.metrics.trackMultiaddrConnection(connection) + * } + * } + * ``` + * + * @example How to track protocol streams + * + * This is something only libp2p connections need to do. + * + * ```typescript + * import { Metrics } from '@libp2p/interface/metrics' + * + * interface MyServiceComponents { + * metrics: Metrics + * } + * + * class MyService { + * private readonly metrics: Metrics + * + * constructor (components: MyServiceComponents) { + * this.metrics = components.metrics + * } + * + * // later + * doSomething () { + * const stream = {} // create a stream + * this.metrics.trackProtocolStream(stream) + * } + * } + * ``` + */ +export interface Metrics { + /** + * Track a newly opened multiaddr connection + */ + trackMultiaddrConnection(maConn: MultiaddrConnection): void + + /** + * Track a newly opened protocol stream + */ + trackProtocolStream(stream: Stream): void + + /** + * Register an arbitrary metric. Call this to set help/labels for metrics + * and update/increment/decrement/etc them by calling methods on the returned + * metric object + */ + registerMetric: ((name: string, options?: MetricOptions) => Metric) & ((name: string, options: CalculatedMetricOptions) => void) + + /** + * Register a a group of related metrics. Call this to set help/labels for + * groups of related metrics that will be updated with by calling `.update`, + * `.increment` and/or `.decrement` methods on the returned metric group object + */ + registerMetricGroup: ((name: string, options?: MetricOptions) => MetricGroup) & ((name: string, options: CalculatedMetricOptions>) => void) + + /** + * Register an arbitrary counter. Call this to set help/labels for counters + * and increment them by calling methods on the returned counter object + */ + registerCounter: ((name: string, options?: MetricOptions) => Counter) & ((name: string, options: CalculatedMetricOptions) => void) + + /** + * Register a a group of related counters. Call this to set help/labels for + * groups of related counters that will be updated with by calling the `.increment` + * method on the returned counter group object + */ + registerCounterGroup: ((name: string, options?: MetricOptions) => CounterGroup) & ((name: string, options: CalculatedMetricOptions>) => void) + + /** + * Register an arbitrary histogram. Call this to set help/labels for histograms + * and observe them by calling methods on the returned histogram object + */ + registerHistogram: ((name: string, options?: HistogramOptions) => Histogram) & ((name: string, options: CalculatedHistogramOptions) => void) + + /** + * Register a a group of related histograms. Call this to set help/labels for + * groups of related histograms that will be updated with by calling the `.observe` + * method on the returned histogram group object + */ + registerHistogramGroup: ((name: string, options?: HistogramOptions) => HistogramGroup) & ((name: string, options: CalculatedHistogramOptions>) => void) + + /** + * Register an arbitrary summary. Call this to set help/labels for summaries + * and observe them by calling methods on the returned summary object + */ + registerSummary: ((name: string, options?: SummaryOptions) => Summary) & ((name: string, options: CalculatedSummaryOptions) => void) + + /** + * Register a a group of related summaries. Call this to set help/labels for + * groups of related summaries that will be updated with by calling the `.observe` + * method on the returned summary group object + */ + registerSummaryGroup: ((name: string, options?: SummaryOptions) => SummaryGroup) & ((name: string, options: CalculatedSummaryOptions>) => void) + + /** + * Wrap a function for tracing purposes. + * + * All functions wrapped like this should accept a final optional options arg. + * + * In order to pass an execution context along to create a multi-layered + * trace, the index of the options arg must be specified. + */ + traceFunction AsyncIterator> (name: string, fn: F, options?: TraceGeneratorFunctionOptions, ReturnType, YieldType>>): F + traceFunction Iterator> (name: string, fn: F, options?: TraceGeneratorFunctionOptions, ReturnType, YieldType>>): F + traceFunction any = (...args: any[]) => any> (name: string, fn: F, options?: TraceFunctionOptions, ReturnType>): F + + /** + * Creates a tracing context that can be used to trace a method call + */ + createTrace(): any +} + +/** + * Infer the yielded type of an (async)iterable + */ +export type YieldType | Iterator> = T extends AsyncIterator ? Y : T extends Iterator ? Y : never + +export type TraceAttributes = Record + +export interface TraceFunctionOptions { + /** + * To construct a trace that spans multiple method invocations, it's necessary + * to pass the trace context onwards as part of the options object. + * + * Specify the index of the options object in the args array here. + * + * @default 0 + */ + optionsIndex?: number + + /** + * Set attributes on the trace by modifying the passed attributes object. + */ + getAttributesFromArgs?(args: A, attributes: TraceAttributes): TraceAttributes + + /** + * Set attributes on the trace by modifying the passed attributes object. The + * object will have previously been passed to `appendAttributesFromArgs` + * and/or `appendAttributesFromYieldedValue` (if defined) + */ + getAttributesFromReturnValue?(value: B, attributes: TraceAttributes): TraceAttributes +} + +export interface TraceGeneratorFunctionOptions extends TraceFunctionOptions { + /** + * Set attributes on the trace by modifying the passed attributes object. The + * object will have previously been passed to `appendAttributesFromArgs` (if + * defined) + */ + getAttributesFromYieldedValue? (value: C, attributes: TraceAttributes, index: number): TraceAttributes +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/multiaddr-connection.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/multiaddr-connection.ts new file mode 100644 index 000000000..3cdcd2d6d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/multiaddr-connection.ts @@ -0,0 +1,34 @@ +import type { MessageStream, MessageStreamTimeline } from './message-stream.ts' +import type { Multiaddr } from '@multiformats/multiaddr' + +export type MultiaddrConnectionDirection = 'inbound' | 'outbound' + +export interface MultiaddrConnectionTimeline extends MessageStreamTimeline { + /** + * When the MultiaddrConnection was upgraded to a Connection - the type of + * connection encryption and multiplexing was negotiated. + */ + upgraded?: number +} + +/** + * A MultiaddrConnection is returned by transports after dialing a peer. It is a + * low-level primitive and is the raw connection without encryption or stream + * multiplexing. + */ +export interface MultiaddrConnection extends MessageStream { + /** + * The address of the remote end of the connection + */ + remoteAddr: Multiaddr + + /** + * When stream life cycle events occurred + */ + timeline: MultiaddrConnectionTimeline + + /** + * Whether this connection is inbound or outbound + */ + direction: MultiaddrConnectionDirection +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-discovery.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-discovery.ts new file mode 100644 index 000000000..a094621b3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-discovery.ts @@ -0,0 +1,42 @@ +import type { PeerInfo } from './peer-info.js' +import type { TypedEventTarget } from 'main-event' + +/** + * Any object that implements this Symbol as a property should return a + * PeerDiscovery instance as the property value, similar to how + * `Symbol.Iterable` can be used to return an `Iterable` from an `Iterator`. + * + * @example + * + * ```TypeScript + * import { peerDiscovery, PeerDiscovery } from '@libp2p/peer-discovery' + * + * class MyPeerDiscoverer implements PeerDiscovery { + * get [peerDiscovery] () { + * return this + * } + * + * // ...other methods + * } + * ``` + */ +export const peerDiscoverySymbol = Symbol.for('@libp2p/peer-discovery') + +/** + * Implementers of this interface can provide a PeerDiscovery implementation to + * interested callers. + */ +export interface PeerDiscoveryProvider { + [peerDiscoverySymbol]: PeerDiscovery +} + +export interface PeerDiscoveryEvents { + peer: CustomEvent +} + +/** + * A class that implements the `PeerDiscovery` interface uses an + * implementation-specific method to discover peers. These peers are then added + * to the peer store for use by other system components and services. + */ +export interface PeerDiscovery extends TypedEventTarget {} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-id.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-id.ts new file mode 100644 index 000000000..2d2f533c1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-id.ts @@ -0,0 +1,163 @@ +import type { Ed25519PublicKey, KeyType, RSAPublicKey, Secp256k1PublicKey } from './keys.js' +import type { CID } from 'multiformats/cid' +import type { MultihashDigest } from 'multiformats/hashes/interface' + +export type PeerIdType = KeyType | string + +/** + * A PeerId generated from an RSA public key - it is a base58btc encoded sha-256 + * hash of the public key. + * + * RSA public keys are too large to pass around freely, instead Ed25519 or + * secp256k1 should be preferred as they can embed their public key in the + * PeerId itself. + * + * @deprecated Ed25519 or secp256k1 keys are preferred to RSA + */ +export interface RSAPeerId { + readonly type: 'RSA' + + /** + * RSA public keys are too large to embed in the multihash commonly used to + * refer to peers, so this will only be defined if the public key has + * previously been found through a routing query or during normal protocol + * operations + */ + readonly publicKey?: RSAPublicKey + + /** + * Returns the multihash from `toMultihash()` as a base58btc encoded string + */ + toString(): string + + /** + * Returns a multihash, the digest of which is the SHA2-256 hash of the public + * key + */ + toMultihash(): MultihashDigest<0x12> + + /** + * Returns a CID with the libp2p key code and the same multihash as + * `toMultihash()` + */ + toCID(): CID + + /** + * Returns true if the passed argument is equivalent to this PeerId + */ + equals(other?: any): boolean +} + +export interface Ed25519PeerId { + readonly type: 'Ed25519' + + /** + * This will always be defined as the public key is embedded in the multihash + * of this PeerId + */ + readonly publicKey: Ed25519PublicKey + + /** + * Returns the multihash from `toMultihash()` as a base58btc encoded string + */ + toString(): string + + /** + * Returns a multihash, the digest of which is the protobuf-encoded public key + * encoded as an identity hash + */ + toMultihash(): MultihashDigest<0x0> + + /** + * Returns a CID with the libp2p key code and the same multihash as + * `toMultihash()` + */ + toCID(): CID + + /** + * Returns true if the passed argument is equivalent to this PeerId + */ + equals(other?: any): boolean +} + +export interface Secp256k1PeerId { + readonly type: 'secp256k1' + + /** + * This will always be defined as the public key is embedded in the multihash + * of this PeerId + */ + readonly publicKey: Secp256k1PublicKey + + /** + * Returns the multihash from `toMultihash()` as a base58btc encoded string + */ + toString(): string + + /** + * Returns a multihash, the digest of which is the protobuf-encoded public key + * encoded as an identity hash + */ + toMultihash(): MultihashDigest<0x0> + + /** + * Returns a CID with the libp2p key code and the same multihash as + * `toMultihash()` + */ + toCID(): CID + + /** + * Returns true if the passed argument is equivalent to this PeerId + */ + equals(other?: any): boolean +} + +export interface URLPeerId { + readonly type: 'url' + + /** + * This will always be undefined as URL Peers do not have public keys + */ + readonly publicKey: undefined + + /** + * Returns CID from `toCID()` encoded as a base36 string + */ + toString(): string + + /** + * Returns a multihash, the digest of which is the URL encoded as an identity + * hash + */ + toMultihash(): MultihashDigest<0x0> + + /** + * Returns a CID with the Transport IPFS Gateway HTTP code and the same + * multihash as `toMultihash()` + */ + toCID(): CID + + /** + * Returns true if the passed argument is equivalent to this PeerId + */ + equals(other?: any): boolean +} + +/** + * This is a union of all known PeerId types - use the `.type` field to + * disambiguate them + */ +export type PeerId = RSAPeerId | Ed25519PeerId | Secp256k1PeerId | URLPeerId + +/** + * All PeerId implementations must use this symbol as the name of a property + * with a boolean `true` value + */ +export const peerIdSymbol = Symbol.for('@libp2p/peer-id') + +/** + * Returns true if the passed argument is a PeerId implementation + */ +export function isPeerId (other?: any): other is PeerId { + return Boolean(other?.[peerIdSymbol]) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-info.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-info.ts new file mode 100644 index 000000000..b0e27c924 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-info.ts @@ -0,0 +1,20 @@ +import type { PeerId } from './peer-id.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * A `PeerInfo` is a lightweight object that represents a remote peer, it can be + * obtained from peer discovery mechanisms, HTTP RPC endpoints, etc. + * + * @see https://docs.libp2p.io/concepts/fundamentals/peers/#peer-info + */ +export interface PeerInfo { + /** + * The identifier of the remote peer + */ + id: PeerId + + /** + * The multiaddrs a peer is listening on + */ + multiaddrs: Multiaddr[] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-routing.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-routing.ts new file mode 100644 index 000000000..616b4755b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-routing.ts @@ -0,0 +1,61 @@ +import type { RoutingOptions } from './index.js' +import type { PeerId } from './peer-id.js' +import type { PeerInfo } from './peer-info.js' + +/** + * Any object that implements this Symbol as a property should return a + * PeerRouting instance as the property value, similar to how `Symbol.Iterable` + * can be used to return an `Iterable` from an `Iterator`. + * + * @example + * + * ```TypeScript + * import { peerRouting, PeerRouting } from '@libp2p/peer-routing' + * + * class MyPeerRouter implements PeerRouting { + * get [peerRouting] () { + * return this + * } + * + * // ...other methods + * } + * ``` + */ +export const peerRoutingSymbol = Symbol.for('@libp2p/peer-routing') + +/** + * Implementers of this interface can provide a PeerRouting implementation to + * interested callers. + */ +export interface PeerRoutingProvider { + [peerRoutingSymbol]: Partial +} + +export interface PeerRouting { + /** + * Searches the network for peer info corresponding to the passed peer id. + * + * @example + * + * ```TypeScript + * // ... + * const peer = await peerRouting.findPeer(peerId, options) + * ``` + */ + findPeer(peerId: PeerId, options?: RoutingOptions): Promise + + /** + * Search the network for peers that are closer to the passed key. Peer + * info should be yielded in ever-increasing closeness to the key. + * + * @example + * + * ```TypeScript + * // Iterate over the closest peers found for the given key + * for await (const peer of peerRouting.getClosestPeers(key)) { + * console.log(peer.id, peer.multiaddrs) + * } + * ``` + */ + getClosestPeers(key: Uint8Array, options?: RoutingOptions): AsyncIterable +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-store.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-store.ts new file mode 100644 index 000000000..e8f53ded5 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/peer-store.ts @@ -0,0 +1,322 @@ +import type { AbortOptions } from './index.ts' +import type { PublicKey } from './keys.js' +import type { PeerId } from './peer-id.js' +import type { PeerInfo } from './peer-info.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * When a peer that is tagged with this prefix disconnects, we will attempt to + * redial it, up to a limit. + * + * To allow multiple components to add/remove their own keep-alive tags without + * accidentally overwriting those of other components, attach a unique suffix to + * the tag, e.g. `keep-alive-circuit-relay` or `keep-alive-kad-dht`, etc. + */ +export const KEEP_ALIVE = 'keep-alive' + +/** + * A multiaddr with an optional flag that indicates if its trustworthy + */ +export interface Address { + /** + * Peer multiaddr + */ + multiaddr: Multiaddr + + /** + * Obtained from a signed peer record + */ + isCertified: boolean +} + +/** + * Data stored in the peer store about peers + */ +export interface Peer { + /** + * Peer's peer-id instance + */ + id: PeerId + + /** + * Peer's addresses containing a list of multiaddrs and a isCertified field + * indicating if the address was loaded from a signed peer record or not + */ + addresses: Address[] + + /** + * Peer's supported protocols + */ + protocols: string[] + + /** + * Peer's metadata map + */ + metadata: Map + + /** + * Tags a peer has + */ + tags: Map + + /** + * The last peer record envelope received + */ + peerRecordEnvelope?: Uint8Array +} + +/** + * Peer data used to update the peer store + */ +export interface PeerData { + /** + * Peer's addresses containing its multiaddrs and metadata - multiaddrs + * passed here can be treated as certified if the `isCertifed` value is + * set to true. + * + * If both addresses and multiaddrs are specified they will be merged + * together with entries in addresses taking precedence. + */ + addresses?: Address[] + + /** + * Peer's multiaddrs - any multiaddrs passed here will be treated as + * uncertified. + * + * If both addresses and multiaddrs are specified they will be merged + * together with entries in addresses taking precedence. + */ + multiaddrs?: Multiaddr[] + + /** + * Peer's supported protocols + */ + protocols?: string[] + + /** + * Peer's metadata map. When merging pass undefined as values to remove metadata. + */ + metadata?: Map | Record + + /** + * Peer tags. When merging pass undefined as values to remove tags. + */ + tags?: Map | Record + + /** + * If this Peer has an RSA key, it's public key can be set with this property. + * + * The byte array should be the protobuf encoded form of the public key. + */ + publicKey?: PublicKey + + /** + * The last peer record envelope received + */ + peerRecordEnvelope?: Uint8Array +} + +export interface TagOptions { + /** + * An optional tag value (1-100) + */ + value?: number + + /** + * An optional duration in ms after which the tag will expire + */ + ttl?: number +} + +export interface Tag { + /** + * The tag value + */ + value: number +} + +/** + * A predicate by which to filter lists of peers + */ +export interface PeerQueryFilter { (peer: Peer): boolean } + +/** + * A predicate by which to sort lists of peers + */ +export interface PeerQueryOrder { (a: Peer, b: Peer): -1 | 0 | 1 } + +/** + * A query for getting lists of peers + */ +export interface PeerQuery extends AbortOptions { + filters?: PeerQueryFilter[] + orders?: PeerQueryOrder[] + limit?: number + offset?: number +} + +export interface ConsumePeerRecordOptions extends AbortOptions { + expectedPeer?: PeerId +} + +export interface PeerStore { + /** + * Loop over every peer - the looping is async because we read from a + * datastore but the peer operation is sync, this is to prevent + * long-lived peer operations causing deadlocks over the datastore + * which can happen if they try to access the peer store during the + * loop + * + * @example + * + * ```TypeScript + * await peerStore.forEach(peer => { + * // ... + * }) + * ``` + */ + forEach(fn: (peer: Peer) => void, query?: PeerQuery): Promise + + /** + * Returns all peers in the peer store. + * + * @example + * + * ```TypeScript + * for (const peer of await peerStore.all()) { + * // ... + * } + * ``` + */ + all(query?: PeerQuery): Promise + + /** + * Delete all data stored for the passed peer + * + * @example + * + * ```TypeScript + * await peerStore.addressBook.set(peerId, multiaddrs) + * await peerStore.addressBook.get(peerId) + * // multiaddrs[] + * + * await peerStore.delete(peerId) + * + * await peerStore.addressBook.get(peerId) + * // [] + * ``` + */ + delete(peerId: PeerId, options?: AbortOptions): Promise + + /** + * Returns true if the passed PeerId is in the peer store + * + * @example + * + * ```TypeScript + * await peerStore.has(peerId) + * // false + * await peerStore.addressBook.add(peerId, multiaddrs) + * await peerStore.has(peerId) + * // true + * ``` + */ + has(peerId: PeerId, options?: AbortOptions): Promise + + /** + * Returns all data stored for the passed PeerId + * + * @example + * + * ```TypeScript + * const peer = await peerStore.get(peerId) + * // { .. } + * ``` + */ + get(peerId: PeerId, options?: AbortOptions): Promise + + /** + * Returns a PeerInfo object for the passed peer id. This is similar to `get` + * except the returned value contains fewer fields and is often used to + * exchange peer information with other systems. + * + * The returned object can be passed to `JSON.stringify` without any + * additional processing. + * + * @see https://docs.libp2p.io/concepts/fundamentals/peers/#peer-info + * + * @example + * + * ```TypeScript + * const peerInfo = await peerStore.getInfo(peerId) + * + * console.info(JSON.stringify(peerInfo)) + * // { + * // id: 'peerId' + * // multiaddrs: [ + * // '...' + * // ] + * // } + * ``` + */ + getInfo (peerId: PeerId, options?: AbortOptions): Promise + + /** + * Adds a peer to the peer store, overwriting any existing data + * + * @example + * + * ```TypeScript + * await peerStore.save(peerId, { + * multiaddrs + * }) + * ``` + */ + save(id: PeerId, data: PeerData, options?: AbortOptions): Promise + + /** + * Adds a peer to the peer store, overwriting only the passed fields + * + * @example + * + * ```TypeScript + * await peerStore.patch(peerId, { + * multiaddrs + * }) + * ``` + */ + patch(id: PeerId, data: PeerData, options?: AbortOptions): Promise + + /** + * Adds a peer to the peer store, deeply merging any existing data. + * + * @example + * + * ```TypeScript + * await peerStore.merge(peerId, { + * multiaddrs + * }) + * ``` + */ + merge(id: PeerId, data: PeerData, options?: AbortOptions): Promise + + /** + * Unmarshal and verify a signed peer record, extract the multiaddrs and + * overwrite the stored addresses for the peer. + * + * Optionally pass an expected PeerId to verify that the peer record was + * signed by that peer. + * + * @example + * + * ```TypeScript + * await peerStore.consumePeerRecord(buf, expectedPeer) + * ``` + */ + consumePeerRecord(buf: Uint8Array, options?: ConsumePeerRecordOptions): Promise + + /** + * @deprecated Pass `expectedPeer` as a property of `options` instead + */ + consumePeerRecord(buf: Uint8Array, expectedPeer?: PeerId, options?: AbortOptions): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/pubsub.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/pubsub.ts new file mode 100644 index 000000000..257eec8cc --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/pubsub.ts @@ -0,0 +1,284 @@ +import type { Stream, PublicKey, PeerId } from './index.js' +import type { Pushable } from 'it-pushable' +import type { TypedEventTarget } from 'main-event' +import type { Uint8ArrayList } from 'uint8arraylist' + +/** + * On the producing side: + * - Build messages with the signature, key (from may be enough for certain inlineable public key types), from and seqno fields. + * + * On the consuming side: + * - Enforce the fields to be present, reject otherwise. + * - Propagate only if the fields are valid and signature can be verified, reject otherwise. + */ +export const StrictSign = 'StrictSign' + +/** + * On the producing side: + * - Build messages without the signature, key, from and seqno fields. + * - The corresponding protobuf key-value pairs are absent from the marshaled message, not just empty. + * + * On the consuming side: + * - Enforce the fields to be absent, reject otherwise. + * - Propagate only if the fields are absent, reject otherwise. + * - A message_id function will not be able to use the above fields, and should instead rely on the data field. A commonplace strategy is to calculate a hash. + */ +export const StrictNoSign = 'StrictNoSign' + +export type SignaturePolicy = typeof StrictSign | typeof StrictNoSign + +export interface SignedMessage { + type: 'signed' + from: PeerId + topic: string + data: Uint8Array + sequenceNumber: bigint + signature: Uint8Array + key: PublicKey +} + +export interface UnsignedMessage { + type: 'unsigned' + topic: string + data: Uint8Array +} + +export type Message = SignedMessage | UnsignedMessage + +export interface PubSubRPCMessage { + from?: Uint8Array + topic?: string + data?: Uint8Array + sequenceNumber?: Uint8Array + signature?: Uint8Array + key?: Uint8Array +} + +export interface PubSubRPCSubscription { + subscribe?: boolean + topic?: string +} + +export interface PubSubRPC { + subscriptions: PubSubRPCSubscription[] + messages: PubSubRPCMessage[] +} + +export interface PeerStreams extends TypedEventTarget { + id: PeerId + protocol: string + outboundStream?: Pushable + inboundStream?: AsyncIterable + isWritable: boolean + + close(): void + write(buf: Uint8Array | Uint8ArrayList): void + attachInboundStream(stream: Stream): AsyncIterable + attachOutboundStream(stream: Stream): Promise> +} + +export interface PubSubInit { + enabled?: boolean + + multicodecs?: string[] + + /** + * defines how signatures should be handled + */ + globalSignaturePolicy?: SignaturePolicy + + /** + * if can relay messages not subscribed + */ + canRelayMessage?: boolean + + /** + * if publish should emit to self, if subscribed + */ + emitSelf?: boolean + + /** + * handle this many incoming pubsub messages concurrently + */ + messageProcessingConcurrency?: number + + /** + * How many parallel incoming streams to allow on the pubsub protocol per-connection + */ + maxInboundStreams?: number + + /** + * How many parallel outgoing streams to allow on the pubsub protocol per-connection + */ + maxOutboundStreams?: number +} + +export interface Subscription { + topic: string + subscribe: boolean +} + +export interface SubscriptionChangeData { + peerId: PeerId + subscriptions: Subscription[] +} + +export interface PubSubEvents { + 'subscription-change': CustomEvent + message: CustomEvent +} + +export interface PublishResult { + recipients: PeerId[] +} + +export enum TopicValidatorResult { + /** + * The message is considered valid, and it should be delivered and forwarded to the network + */ + Accept = 'accept', + /** + * The message is neither delivered nor forwarded to the network + */ + Ignore = 'ignore', + /** + * The message is considered invalid, and it should be rejected + */ + Reject = 'reject' +} + +export interface TopicValidatorFn { + (peer: PeerId, message: Message): TopicValidatorResult | Promise +} + +/** + * @deprecated This will be removed from `@libp2p/interface` in a future release, pubsub implementations should declare their own types + */ +export interface PubSub = PubSubEvents> extends TypedEventTarget { + /** + * The global signature policy controls whether or not we sill send and receive + * signed or unsigned messages. + * + * Signed messages prevent spoofing message senders and should be preferred to + * using unsigned messages. + */ + globalSignaturePolicy: typeof StrictSign | typeof StrictNoSign + + /** + * A list of multicodecs that contain the pubsub protocol name. + */ + multicodecs: string[] + + /** + * Pubsub routers support message validators per topic, which will validate the message + * before its propagations. They are stored in a map where keys are the topic name and + * values are the validators. + * + * @example + * + * ```TypeScript + * const topic = 'topic' + * const validateMessage = (msgTopic, msg) => { + * const input = uint8ArrayToString(msg.data) + * const validInputs = ['a', 'b', 'c'] + * + * if (!validInputs.includes(input)) { + * throw new Error('no valid input received') + * } + * } + * libp2p.pubsub.topicValidators.set(topic, validateMessage) + * ``` + */ + topicValidators: Map + + getPeers(): PeerId[] + + /** + * Gets a list of topics the node is subscribed to. + * + * ```TypeScript + * const topics = libp2p.pubsub.getTopics() + * ``` + */ + getTopics(): string[] + + /** + * Subscribes to a pubsub topic. + * + * @example + * + * ```TypeScript + * const topic = 'topic' + * const handler = (msg) => { + * if (msg.topic === topic) { + * // msg.data - pubsub data received + * } + * } + * + * libp2p.pubsub.addEventListener('message', handler) + * libp2p.pubsub.subscribe(topic) + * ``` + */ + subscribe(topic: string): void + + /** + * Unsubscribes from a pubsub topic. + * + * @example + * + * ```TypeScript + * const topic = 'topic' + * const handler = (msg) => { + * // msg.data - pubsub data received + * } + * + * libp2p.pubsub.removeEventListener(topic handler) + * libp2p.pubsub.unsubscribe(topic) + * ``` + */ + unsubscribe(topic: string): void + + /** + * Gets a list of the PeerIds that are subscribed to one topic. + * + * @example + * + * ```TypeScript + * const peerIds = libp2p.pubsub.getSubscribers(topic) + * ``` + */ + getSubscribers(topic: string): PeerId[] + + /** + * Publishes messages to the given topic. + * + * @example + * + * ```TypeScript + * const topic = 'topic' + * const data = uint8ArrayFromString('data') + * + * await libp2p.pubsub.publish(topic, data) + * ``` + */ + publish(topic: string, data: Uint8Array): Promise +} + +export interface PeerStreamEvents { + 'stream:inbound': CustomEvent + 'stream:outbound': CustomEvent + close: CustomEvent +} + +/** + * All Pubsub implementations must use this symbol as the name of a property + * with a boolean `true` value + */ +export const pubSubSymbol = Symbol.for('@libp2p/pubsub') + +/** + * Returns true if the passed argument is a PubSub implementation + */ +export function isPubSub (obj?: any): obj is PubSub { + return Boolean(obj?.[pubSubSymbol]) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/record.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/record.ts new file mode 100644 index 000000000..715a339e8 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/record.ts @@ -0,0 +1,64 @@ +import type { PublicKey } from './keys.js' +import type { Uint8ArrayList } from 'uint8arraylist' + +/** + * Record is the base implementation of a record that can be used as the payload of a libp2p envelope. + */ +export interface Record { + /** + * signature domain. + */ + domain: string + /** + * identifier of the type of record + */ + codec: Uint8Array + /** + * Marshal a record to be used in an envelope. + */ + marshal(): Uint8Array + /** + * Verifies if the other provided Record is identical to this one. + */ + equals(other: Record): boolean +} + +/** + * A message with a signed payload. + */ +export interface Envelope { + /** + * The public key of the keypair used to sign the payload + */ + publicKey: PublicKey + + /** + * How the payload should be interpreted + */ + payloadType: Uint8Array | Uint8ArrayList + + /** + * The contents of the envelope + */ + payload: Uint8Array + + /** + * A signature that can be used to verify the payload is intact + */ + signature: Uint8Array | Uint8ArrayList + + /** + * Serialize the envelope to a binary format + */ + marshal(): Uint8Array + + /** + * Use the public key to validate that the payload is intact + */ + validate(domain: string): Promise + + /** + * Returns true if this envelope has equivalency with the passed object + */ + equals(other?: Envelope): boolean +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/startable.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/startable.ts new file mode 100644 index 000000000..010f1d626 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/startable.ts @@ -0,0 +1,165 @@ +/** + * Implemented by components that have a life cycle + */ +export interface Startable { + /** + * If implemented, this method will be invoked before the start method. + * + * It should not assume any other components have been started. + */ + beforeStart?(): void | Promise + + /** + * This method will be invoked to start the component. + * + * It should not assume that any other components have been started. + */ + start(): void | Promise + + /** + * If implemented, this method will be invoked after the start method. + * + * All other components will have had their start method invoked before this method is called. + */ + afterStart?(): void | Promise + + /** + * If implemented, this method will be invoked before the stop method. + * + * Any other components will still be running when this method is called. + */ + beforeStop?(): void | Promise + + /** + * This method will be invoked to stop the component. + * + * It should not assume any other components are running when it is called. + */ + stop(): void | Promise + + /** + * If implemented, this method will be invoked after the stop method. + * + * All other components will have had their stop method invoked before this method is called. + */ + afterStop?(): void | Promise +} + +/** + * Returns `true` if the object has type overlap with `Startable` + */ +export function isStartable (obj?: any): obj is Startable { + return obj != null && typeof obj.start === 'function' && typeof obj.stop === 'function' +} + +/** + * A function that can be used to start and objects passed to it. This checks + * that an object is startable before invoking its lifecycle methods so it is + * safe to pass non-`Startable`s in. + * + * @example + * + * ```TypeScript + * import { start } from '@libp2p/interface' + * import type { Startable } from '@libp2p/interface' + * + * const startable: Startable = { + * start: () => {}, + * stop: () => {} + * } + * + * const notStartable = 5 + * + * await start( + * startable, + * notStartable + * ) + * ``` + */ +export async function start (...objs: any[]): Promise { + const startables: Startable[] = [] + + for (const obj of objs) { + if (isStartable(obj)) { + startables.push(obj) + } + } + + await Promise.all( + startables.map(async s => { + if (s.beforeStart != null) { + await s.beforeStart() + } + }) + ) + + await Promise.all( + startables.map(async s => { + await s.start() + }) + ) + + await Promise.all( + startables.map(async s => { + if (s.afterStart != null) { + await s.afterStart() + } + }) + ) +} + +/** + * A function that can be used to stop and objects passed to it. This checks + * that an object is startable before invoking its lifecycle methods so it is + * safe to pass non-`Startable`s in. + * + * @example + * + * ```TypeScript + * import { stop } from '@libp2p/interface' + * import type { Startable } from '@libp2p/interface' + * + * const startable: Startable = { + * start: () => {}, + * stop: () => {} + * } + * + * const notStartable = 5 + * + * await stop( + * startable, + * notStartable + * ) + * ``` + */ +export async function stop (...objs: any[]): Promise { + const startables: Startable[] = [] + + for (const obj of objs) { + if (isStartable(obj)) { + startables.push(obj) + } + } + + await Promise.all( + startables.map(async s => { + if (s.beforeStop != null) { + await s.beforeStop() + } + }) + ) + + await Promise.all( + startables.map(async s => { + await s.stop() + }) + ) + + await Promise.all( + startables.map(async s => { + if (s.afterStop != null) { + await s.afterStop() + } + }) + ) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream-handler.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream-handler.ts new file mode 100644 index 000000000..9cefd09e5 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream-handler.ts @@ -0,0 +1,48 @@ +import type { AbortOptions, Connection, Stream } from './index.ts' + +export interface StreamHandler { + /** + * A callback function that accepts the incoming stream data + */ + (stream: Stream, connection: Connection): void | Promise +} + +export interface StreamHandlerOptions extends AbortOptions { + /** + * How many incoming streams can be open for this protocol at the same time on each connection + * + * @default 32 + */ + maxInboundStreams?: number + + /** + * How many outgoing streams can be open for this protocol at the same time on each connection + * + * @default 64 + */ + maxOutboundStreams?: number + + /** + * Opt-in to running over connections with limits on how much data can be + * transferred or how long it can be open for. + */ + runOnLimitedConnection?: boolean + + /** + * If `true`, and a handler is already registered for the specified + * protocol(s), the existing handler will be discarded. + */ + force?: true +} + +export interface StreamHandlerRecord { + /** + * The handler that was registered to handle streams opened on the protocol + */ + handler: StreamHandler + + /** + * The options that were used to register the stream handler + */ + options: StreamHandlerOptions +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream-muxer.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream-muxer.ts new file mode 100644 index 000000000..d1bc25119 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream-muxer.ts @@ -0,0 +1,72 @@ +import type { Uint8ArrayList } from 'uint8arraylist' +import type { Stream, MultiaddrConnection, TypedEventTarget, MessageStream } from './index.js' +import type { AbortOptions } from '@multiformats/multiaddr' + +export interface StreamMuxerFactory { + /** + * The protocol used to select this muxer during connection opening + */ + protocol: string + + /** + * Creates a new stream muxer to be used with a new connection + */ + createStreamMuxer(maConn: MessageStream): Muxer +} + +export interface StreamMuxerEvents { + /** + * An incoming stream was created + */ + stream: CustomEvent +} + +export interface CreateStreamOptions extends AbortOptions { + /** + * If a single protocol was requested and the muxer has support for this, + * pre-negotiate the protocol using this value, otherwise multistream-select + * will be run over the stream after opening. + */ + protocol?: string +} + +export type StreamMuxerStatus = 'open' | 'closing' | 'closed' + +/** + * A libp2p stream muxer + */ +export interface StreamMuxer extends TypedEventTarget> { + /** + * The protocol used to select this muxer during connection opening + */ + protocol: string + + /** + * A list of streams that are currently open + */ + streams: MuxedStream[] + + /** + * The status of the muxer + */ + status: StreamMuxerStatus + + /** + * Create a new stream + */ + createStream(options?: CreateStreamOptions): MuxedStream | Promise + + /** + * Immediately close the muxer, abort every open stream and discard any + * unsent/unread data. + */ + abort (err: Error): void + + /** + * Gracefully close the muxer. All open streams will be gracefully closed, and + * the returned promise will either resolve when any/all unsent data has been + * sent, or it will reject if the passed abort signal fires before this + * happens. + */ + close (options?: AbortOptions): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream.ts new file mode 100644 index 000000000..a59cf4b3a --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/stream.ts @@ -0,0 +1,20 @@ +import type { MessageStream } from './message-stream.js' + +/** + * A Stream is a lightweight data channel between two peers that can be written + * to and read from at both ends. + * + * It may be encrypted and multiplexed depending on the configuration of the + * nodes. + */ +export interface Stream extends MessageStream { + /** + * Unique identifier for a stream. Identifiers are not unique across muxers. + */ + id: string + + /** + * The protocol negotiated for this stream + */ + protocol: string +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/topology.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/topology.ts new file mode 100644 index 000000000..bc49a1916 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/topology.ts @@ -0,0 +1,50 @@ +import type { Connection } from './connection.js' +import type { PeerId } from './peer-id.js' + +/** + * A topology filter - this can be used by topologies to ensure they do not + * receive duplicate notifications of individual peers + * + * @see https://libp2p.github.io/js-libp2p/functions/_libp2p_peer_collections.peerFilter-1.html + */ +export interface TopologyFilter { + has (peerId: PeerId): boolean + add (peerId: PeerId): void + remove (peerId: PeerId): void +} + +/** + * A topology is a network overlay that contains a subset of peers in the + * complete network. + * + * It is a way to be notified when peers that support a given protocol connect + * to or disconnect from the current node. + */ +export interface Topology { + /** + * An optional filter can prevent duplicate topology notifications for the + * same peer. + */ + filter?: TopologyFilter + + /** + * If true, invoke `onConnect` for this topology on limited connections, e.g. + * ones with limits on how much data can be transferred or how long they can + * be open for. + * + * @default false + */ + notifyOnLimitedConnection?: boolean + + /** + * Invoked when a new connection is opened to a peer that supports the + * registered protocol + */ + onConnect?(peerId: PeerId, conn: Connection): void + + /** + * Invoked when the last connection to a peer that supports the registered + * protocol closes + */ + onDisconnect?(peerId: PeerId): void +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/transport.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/transport.ts new file mode 100644 index 000000000..c00e78040 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/src/transport.ts @@ -0,0 +1,225 @@ +import type { AbortOptions, ClearableSignal, ConnectionEncrypter, MultiaddrConnection, Connection, ConnectionLimits, StreamMuxerFactory, PeerId } from './index.js' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { TypedEventTarget } from 'main-event' +import type { ProgressOptions, ProgressEvent } from 'progress-events' + +export interface ListenerEvents { + /** + * This event signals to the transport manager that the listening addresses + * have changed and may be emitted at any point and/or multiple times + */ + listening: CustomEvent + + /** + * Emitted if listening on an address failed + */ + error: CustomEvent + + /** + * Emitted when the listener has been shut down, has no open connections and + * will no longer accept new connections + */ + close: CustomEvent +} + +export interface Listener extends TypedEventTarget { + /** + * Start a listener + */ + listen(multiaddr: Multiaddr): Promise + + /** + * Get listen addresses + */ + getAddrs(): Multiaddr[] + + /** + * Close listener + * + * @returns {Promise} + */ + close(): Promise + + /** + * Allows transports to amend announce addresses - to add certificate hashes + * or other metadata that cannot be known before runtime + */ + updateAnnounceAddrs(addrs: Multiaddr[]): void +} + +export const transportSymbol = Symbol.for('@libp2p/transport') + +/** + * A filter that acts on a list of multiaddrs + */ +export interface MultiaddrFilter { + (multiaddrs: Multiaddr[]): Multiaddr[] +} + +export interface CreateListenerOptions { + /** + * The upgrader turns a MultiaddrConnection into a Connection and notifies + * other libp2p components about a new incoming connection. + */ + upgrader: Upgrader +} + +export interface DialTransportOptions extends Required, ProgressOptions { + /** + * The upgrader turns a MultiaddrConnection into a Connection which should be + * returned by the transport's dial method + */ + upgrader: Upgrader +} + +/** + * A libp2p transport offers dial and listen methods to establish connections. + */ +export interface Transport { + /** + * Used to identify the transport + */ + [Symbol.toStringTag]: string + + /** + * Used by the isTransport function + */ + [transportSymbol]: true + + /** + * Dial a given multiaddr. + */ + dial(ma: Multiaddr, options: DialTransportOptions): Promise + + /** + * Create transport listeners. + */ + createListener(options: CreateListenerOptions): Listener + + /** + * Takes a list of `Multiaddr`s and returns only addresses that are valid for + * the transport to listen on + */ + listenFilter: MultiaddrFilter + + /** + * Takes a list of `Multiaddr`s and returns only addresses that are valid for + * the transport to dial + */ + dialFilter: MultiaddrFilter +} + +/** + * Used to disambiguate transport implementations + */ +export function isTransport (other?: any): other is Transport { + return other != null && Boolean(other[transportSymbol]) +} + +/** + * Enum Transport Manager Fault Tolerance values + */ +export enum FaultTolerance { + /** + * should be used for failing in any listen circumstance + */ + FATAL_ALL = 0, + + /** + * should be used for not failing when not listening + */ + NO_FATAL +} + +/** + * Options accepted by the upgrader during connection establishment + */ +export interface UpgraderOptions extends ProgressOptions, Required { + /** + * If true no connection protection will be performed on the connection. + */ + skipProtection?: boolean + + /** + * By default a stream muxer protocol will be negotiated via multi-stream + * select after an encryption protocol has been agreed on. + * + * If a transport provides it's own stream muxing facility pass a muxer + * factory instance here to skip muxer negotiation. + */ + muxerFactory?: StreamMuxerFactory + + /** + * If the connection is to have limits applied to it, pass them here + */ + limits?: ConnectionLimits + + /** + * Multi-stream select is a initiator/responder protocol. By default a + * connection returned from `upgrader.upgradeOutbound` will be the initiator + * and one returned from `upgrader.upgradeInbound` will be the responder. + * + * Pass a value here to override the default. + */ + initiator?: boolean +} + +/** + * Options accepted by the upgrader during connection establishment + */ +export interface UpgraderWithoutEncryptionOptions extends UpgraderOptions { + /** + * If true the invoking transport is expected to implement it's own encryption + * and an encryption protocol will not attempted to be negotiated via + * multi-stream select + */ + skipEncryption: true + + /** + * If `skipEncryption` is true, a remote PeerId must be supplied + */ + remotePeer: PeerId +} + +export type InboundConnectionUpgradeEvents = +ProgressEvent<'upgrader:encrypt-inbound-connection'> | +ProgressEvent<'upgrader:multiplex-inbound-connection'> + +export type OutboundConnectionUpgradeEvents = +ProgressEvent<'upgrader:encrypt-outbound-connection'> | +ProgressEvent<'upgrader:multiplex-outbound-connection'> + +export interface Upgrader { + /** + * Upgrades an outbound connection created by the `dial` method of a transport + */ + upgradeOutbound(maConn: MultiaddrConnection, opts: UpgraderOptions): Promise + upgradeOutbound(maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise + + /** + * Upgrades an inbound connection received by a transport listener and + * notifies other libp2p components about the new connection + */ + upgradeInbound(maConn: MultiaddrConnection, opts: UpgraderOptions): Promise + upgradeInbound(maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise + + /** + * Used by transports that perform part of the upgrade process themselves and + * do some async work. This allows configuring inbound upgrade timeouts from a + * single location. + * + * Regular transports should just pass the signal from their shutdown + * controller to `upgradeInbound`. + */ + createInboundAbortSignal (signal: AbortSignal): ClearableSignal + + /** + * Returns configured stream muxers + */ + getStreamMuxers (): Map + + /** + * Returns configured connection encrypters + */ + getConnectionEncrypters (): Map +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/interface/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/.aegir.js b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/.aegir.js new file mode 100644 index 000000000..b3c0d4758 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/.aegir.js @@ -0,0 +1,11 @@ +/** @type {import('aegir').PartialOptions} */ +export default { + build: { + bundlesizeMax: '95KB' + }, + dependencyCheck: { + ignore: [ + 'react-native' + ] + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/CHANGELOG.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/CHANGELOG.md new file mode 100644 index 000000000..ebd06e55d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/CHANGELOG.md @@ -0,0 +1,4770 @@ +### [0.46.10](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.9...libp2p-v0.46.10) (2023-09-10) + + +### Bug Fixes + +* **libp2p:** only dial one address at a time for peers ([#2028](https://www.github.com/libp2p/js-libp2p/issues/2028)) ([73b87c5](https://www.github.com/libp2p/js-libp2p/commit/73b87c5a1474f9acd47989b675724ea64d02c7b9)) +* **libp2p:** sort addresses to dial as public, then relay ([#2031](https://www.github.com/libp2p/js-libp2p/issues/2031)) ([5294f14](https://www.github.com/libp2p/js-libp2p/commit/5294f14caa314bb150554afff3a7ff45d2bf17ba)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/peer-record bumped from ^6.0.3 to ^6.0.4 + * @libp2p/peer-store bumped from ^9.0.3 to ^9.0.4 + * @libp2p/utils bumped from ^4.0.2 to ^4.0.3 + * devDependencies + * @libp2p/kad-dht bumped from ^10.0.5 to ^10.0.6 + * @libp2p/mdns bumped from ^9.0.6 to ^9.0.7 + * @libp2p/tcp bumped from ^8.0.5 to ^8.0.6 + * @libp2p/websockets bumped from ^7.0.5 to ^7.0.6 + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/multistream-select bumped from ^4.0.8 to ^4.0.9 + * devDependencies + * @libp2p/bootstrap bumped from ^10.0.1 to ^10.0.2 + * @libp2p/circuit-relay-v2 bumped from ^1.0.1 to ^1.0.2 + * @libp2p/floodsub bumped from ^8.0.15 to ^8.0.16 + * @libp2p/interface-compliance-tests bumped from ^5.0.1 to ^5.0.2 + * @libp2p/kad-dht bumped from ^11.0.1 to ^11.0.2 + * @libp2p/mdns bumped from ^10.0.1 to ^10.0.2 + * @libp2p/mplex bumped from ^10.0.1 to ^10.0.2 + * @libp2p/plaintext bumped from ^1.0.1 to ^1.0.2 + * @libp2p/tcp bumped from ^9.0.1 to ^9.0.2 + * @libp2p/websockets bumped from ^8.0.1 to ^8.0.2 + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^0.1.11 to ^1.0.0 + * devDependencies + * @libp2p/bootstrap bumped from ^10.0.2 to ^10.0.3 + * @libp2p/circuit-relay-v2 bumped from ^1.0.2 to ^1.0.3 + * @libp2p/identify bumped from ^1.0.1 to ^1.0.2 + * @libp2p/interface-compliance-tests bumped from ^5.0.2 to ^5.0.3 + * @libp2p/kad-dht bumped from ^11.0.2 to ^11.0.3 + * @libp2p/mdns bumped from ^10.0.2 to ^10.0.3 + * @libp2p/mplex bumped from ^10.0.2 to ^10.0.3 + * @libp2p/plaintext bumped from ^1.0.2 to ^1.0.3 + * @libp2p/tcp bumped from ^9.0.2 to ^9.0.3 + * @libp2p/websockets bumped from ^8.0.2 to ^8.0.3 + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^1.0.0 to ^1.0.1 + * @libp2p/multistream-select bumped from ^4.0.9 to ^5.0.0 + * @libp2p/peer-collections bumped from ^4.0.10 to ^5.0.0 + * @libp2p/peer-id-factory bumped from ^3.0.10 to ^4.0.0 + * @libp2p/peer-store bumped from ^9.0.11 to ^10.0.0 + * @libp2p/utils bumped from ^5.0.1 to ^5.0.2 + * devDependencies + * @libp2p/bootstrap bumped from ^10.0.3 to ^10.0.4 + * @libp2p/circuit-relay-v2 bumped from ^1.0.3 to ^1.0.4 + * @libp2p/identify bumped from ^1.0.2 to ^1.0.3 + * @libp2p/interface-compliance-tests bumped from ^5.0.3 to ^5.0.4 + * @libp2p/kad-dht bumped from ^11.0.3 to ^11.0.4 + * @libp2p/mdns bumped from ^10.0.3 to ^10.0.4 + * @libp2p/mplex bumped from ^10.0.3 to ^10.0.4 + * @libp2p/plaintext bumped from ^1.0.3 to ^1.0.4 + * @libp2p/tcp bumped from ^9.0.3 to ^9.0.4 + * @libp2p/websockets bumped from ^8.0.3 to ^8.0.4 + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^1.0.1 to ^1.0.2 + * @libp2p/peer-collections bumped from ^5.0.0 to ^5.1.0 + * @libp2p/peer-store bumped from ^10.0.0 to ^10.0.1 + * devDependencies + * @libp2p/bootstrap bumped from ^10.0.5 to ^10.0.6 + * @libp2p/circuit-relay-v2 bumped from ^1.0.5 to ^1.0.6 + * @libp2p/identify bumped from ^1.0.4 to ^1.0.5 + * @libp2p/interface-compliance-tests bumped from ^5.0.5 to ^5.0.6 + * @libp2p/kad-dht bumped from ^11.0.5 to ^11.0.6 + * @libp2p/mdns bumped from ^10.0.5 to ^10.0.6 + * @libp2p/mplex bumped from ^10.0.5 to ^10.0.6 + * @libp2p/plaintext bumped from ^1.0.5 to ^1.0.6 + * @libp2p/tcp bumped from ^9.0.5 to ^9.0.6 + * @libp2p/websockets bumped from ^8.0.5 to ^8.0.6 + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/peer-store bumped from ^10.0.9 to ^10.0.10 + * @libp2p/utils bumped from ^5.2.4 to ^5.2.5 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.14 to ^1.0.15 + * @libp2p/identify bumped from ^1.0.13 to ^1.0.14 + * @libp2p/interface-compliance-tests bumped from ^5.3.0 to ^5.3.1 + * @libp2p/mplex bumped from ^10.0.14 to ^10.0.15 + * @libp2p/plaintext bumped from ^1.0.14 to ^1.0.15 + * @libp2p/tcp bumped from ^9.0.14 to ^9.0.15 + * @libp2p/websockets bumped from ^8.0.14 to ^8.0.15 + +## [2.9.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.14...libp2p-v2.9.0) (2025-07-08) + + +### Features + +* add isLibp2p function for type guarding ([#3211](https://github.com/libp2p/js-libp2p/issues/3211)) ([87e5d59](https://github.com/libp2p/js-libp2p/commit/87e5d5938368fee2b34ed386ab42294307f9bf6e)) + +## [2.8.14](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.13...libp2p-v2.8.14) (2025-07-07) + + +### Dependencies + +* update @multiformats/multiaddr-matcher dep to 2.x.x ([#3208](https://github.com/libp2p/js-libp2p/issues/3208)) ([57e7fa4](https://github.com/libp2p/js-libp2p/commit/57e7fa4413a0e19799b5917bad6743800c77e1f7)) + +## [2.8.13](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.12...libp2p-v2.8.13) (2025-07-03) + + +### Bug Fixes + +* do not close relay connection after WebRTC upgrade ([#3205](https://github.com/libp2p/js-libp2p/issues/3205)) ([cfe2be4](https://github.com/libp2p/js-libp2p/commit/cfe2be4c9319b68f8e68df8021b9ee3c1a7236fd)) + +## [2.8.12](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.11...libp2p-v2.8.12) (2025-06-25) + + +### Bug Fixes + +* add multiaddr resolvers ([#3200](https://github.com/libp2p/js-libp2p/issues/3200)) ([1c1c49e](https://github.com/libp2p/js-libp2p/commit/1c1c49ef4f25dcd8925d134f7e185658c10d2d6b)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.1.6 to ^5.1.7 + * @libp2p/interface bumped from ^2.10.4 to ^2.10.5 + * @libp2p/interface-internal bumped from ^2.3.17 to ^2.3.18 + * @libp2p/logger bumped from ^5.1.20 to ^5.1.21 + * @libp2p/multistream-select bumped from ^6.0.27 to ^6.0.28 + * @libp2p/peer-collections bumped from ^6.0.33 to ^6.0.34 + * @libp2p/peer-id bumped from ^5.1.7 to ^5.1.8 + * @libp2p/peer-store bumped from ^11.2.5 to ^11.2.6 + * @libp2p/utils bumped from ^6.7.0 to ^6.7.1 + +## [2.8.11](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.10...libp2p-v2.8.11) (2025-06-17) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.3.16 to ^2.3.17 + * @libp2p/peer-collections bumped from ^6.0.32 to ^6.0.33 + * @libp2p/peer-store bumped from ^11.2.4 to ^11.2.5 + * @libp2p/utils bumped from ^6.6.7 to ^6.7.0 + +## [2.8.10](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.9...libp2p-v2.8.10) (2025-06-16) + + +### Bug Fixes + +* update multiaddr ([#3184](https://github.com/libp2p/js-libp2p/issues/3184)) ([6c42ea6](https://github.com/libp2p/js-libp2p/commit/6c42ea64a6e22028a87ecb3422e418e99ff09279)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.1.5 to ^5.1.6 + * @libp2p/interface bumped from ^2.10.3 to ^2.10.4 + * @libp2p/interface-internal bumped from ^2.3.15 to ^2.3.16 + * @libp2p/logger bumped from ^5.1.19 to ^5.1.20 + * @libp2p/multistream-select bumped from ^6.0.26 to ^6.0.27 + * @libp2p/peer-collections bumped from ^6.0.31 to ^6.0.32 + * @libp2p/peer-id bumped from ^5.1.6 to ^5.1.7 + * @libp2p/peer-store bumped from ^11.2.3 to ^11.2.4 + * @libp2p/utils bumped from ^6.6.6 to ^6.6.7 + +## [2.8.9](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.8...libp2p-v2.8.9) (2025-06-03) + + +### Bug Fixes + +* abort async operations ([#3152](https://github.com/libp2p/js-libp2p/issues/3152)) ([8efb065](https://github.com/libp2p/js-libp2p/commit/8efb065d216fc587605a01d0b2ff93259c7ff723)) +* add tracking for long-lived maps ([#3158](https://github.com/libp2p/js-libp2p/issues/3158)) ([3528df8](https://github.com/libp2p/js-libp2p/commit/3528df8295ed0ccceff5cfac6a3d35d8f2480765)) +* deduplicate typed event target ([#3170](https://github.com/libp2p/js-libp2p/issues/3170)) ([cc7b34c](https://github.com/libp2p/js-libp2p/commit/cc7b34c0fe3ac5745fd082ae0198b8742371a412)) +* pass metrics to peerstore ([#3164](https://github.com/libp2p/js-libp2p/issues/3164)) ([307d0ba](https://github.com/libp2p/js-libp2p/commit/307d0ba58b7301f3fc5f6c86066606d63b72c882)) +* report dial errors to metrics ([#3165](https://github.com/libp2p/js-libp2p/issues/3165)) ([ec73d59](https://github.com/libp2p/js-libp2p/commit/ec73d59a68947cbedc3367deceec21a1e59f21db)) + + +### Documentation + +* update typedoc config ([#3146](https://github.com/libp2p/js-libp2p/issues/3146)) ([14dbebe](https://github.com/libp2p/js-libp2p/commit/14dbebea8bd17addadac730afec0fa3b1cc6334a)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.1.4 to ^5.1.5 + * @libp2p/interface bumped from ^2.10.2 to ^2.10.3 + * @libp2p/interface-internal bumped from ^2.3.14 to ^2.3.15 + * @libp2p/logger bumped from ^5.1.18 to ^5.1.19 + * @libp2p/multistream-select bumped from ^6.0.25 to ^6.0.26 + * @libp2p/peer-collections bumped from ^6.0.30 to ^6.0.31 + * @libp2p/peer-id bumped from ^5.1.5 to ^5.1.6 + * @libp2p/peer-store bumped from ^11.2.2 to ^11.2.3 + * @libp2p/utils bumped from ^6.6.5 to ^6.6.6 + +## [2.8.8](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.7...libp2p-v2.8.8) (2025-05-22) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.1.3 to ^5.1.4 + * @libp2p/interface bumped from ^2.10.1 to ^2.10.2 + * @libp2p/interface-internal bumped from ^2.3.13 to ^2.3.14 + * @libp2p/logger bumped from ^5.1.17 to ^5.1.18 + * @libp2p/multistream-select bumped from ^6.0.24 to ^6.0.25 + * @libp2p/peer-collections bumped from ^6.0.29 to ^6.0.30 + * @libp2p/peer-id bumped from ^5.1.4 to ^5.1.5 + * @libp2p/peer-store bumped from ^11.2.1 to ^11.2.2 + * @libp2p/utils bumped from ^6.6.4 to ^6.6.5 + +## [2.8.7](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.6...libp2p-v2.8.7) (2025-05-20) + + +### Dependencies + +* bump sinon from 19.0.5 to 20.0.0 ([#3112](https://github.com/libp2p/js-libp2p/issues/3112)) ([d1ce677](https://github.com/libp2p/js-libp2p/commit/d1ce6774d8f7c338f15a05f80d09e361d21e7586)) +* update aegir, fix all linting issues ([#3110](https://github.com/libp2p/js-libp2p/issues/3110)) ([510b033](https://github.com/libp2p/js-libp2p/commit/510b033f6b15358c7fae21486c3b09e730aa26cd)) +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.1.2 to ^5.1.3 + * @libp2p/interface bumped from ^2.10.0 to ^2.10.1 + * @libp2p/interface-internal bumped from ^2.3.12 to ^2.3.13 + * @libp2p/logger bumped from ^5.1.16 to ^5.1.17 + * @libp2p/multistream-select bumped from ^6.0.23 to ^6.0.24 + * @libp2p/peer-collections bumped from ^6.0.28 to ^6.0.29 + * @libp2p/peer-id bumped from ^5.1.3 to ^5.1.4 + * @libp2p/peer-store bumped from ^11.2.0 to ^11.2.1 + * @libp2p/utils bumped from ^6.6.3 to ^6.6.4 + +## [2.8.6](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.5...libp2p-v2.8.6) (2025-05-19) + + +### Bug Fixes + +* allow partial routing implementations ([#3093](https://github.com/libp2p/js-libp2p/issues/3093)) ([772b401](https://github.com/libp2p/js-libp2p/commit/772b4011e18ab7bbfc5aeeefd9e13e168d5d9579)) +* increase default adaptive timeout ([#3104](https://github.com/libp2p/js-libp2p/issues/3104)) ([a01606e](https://github.com/libp2p/js-libp2p/commit/a01606e1a370843f5bc3cf0b1a45d6f5eac96194)) + + +### Documentation + +* update comments in interface module and elsewhere ([#3107](https://github.com/libp2p/js-libp2p/issues/3107)) ([32627c8](https://github.com/libp2p/js-libp2p/commit/32627c8767587f7e8df88a700933ece6d5f5c3c4)), closes [#2112](https://github.com/libp2p/js-libp2p/issues/2112) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.1.1 to ^5.1.2 + * @libp2p/interface bumped from ^2.9.0 to ^2.10.0 + * @libp2p/interface-internal bumped from ^2.3.11 to ^2.3.12 + * @libp2p/logger bumped from ^5.1.15 to ^5.1.16 + * @libp2p/multistream-select bumped from ^6.0.22 to ^6.0.23 + * @libp2p/peer-collections bumped from ^6.0.27 to ^6.0.28 + * @libp2p/peer-id bumped from ^5.1.2 to ^5.1.3 + * @libp2p/peer-store bumped from ^11.1.4 to ^11.2.0 + * @libp2p/utils bumped from ^6.6.2 to ^6.6.3 + +## [2.8.5](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.4...libp2p-v2.8.5) (2025-04-17) + + +### Bug Fixes + +* update append announce addresses ([#3085](https://github.com/libp2p/js-libp2p/issues/3085)) ([afa5c9f](https://github.com/libp2p/js-libp2p/commit/afa5c9f598297fef9a5dd50d856868f190629837)), closes [#3080](https://github.com/libp2p/js-libp2p/issues/3080) + +## [2.8.4](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.3...libp2p-v2.8.4) (2025-04-16) + + +### Bug Fixes + +* allow empty error events ([#3082](https://github.com/libp2p/js-libp2p/issues/3082)) ([ae7d867](https://github.com/libp2p/js-libp2p/commit/ae7d867f25a7a730bbd551eb1167a6c148975d86)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.1.0 to ^5.1.1 + * @libp2p/interface bumped from ^2.8.0 to ^2.9.0 + * @libp2p/interface-internal bumped from ^2.3.10 to ^2.3.11 + * @libp2p/logger bumped from ^5.1.14 to ^5.1.15 + * @libp2p/multistream-select bumped from ^6.0.21 to ^6.0.22 + * @libp2p/peer-collections bumped from ^6.0.26 to ^6.0.27 + * @libp2p/peer-id bumped from ^5.1.1 to ^5.1.2 + * @libp2p/peer-store bumped from ^11.1.3 to ^11.1.4 + * @libp2p/utils bumped from ^6.6.1 to ^6.6.2 + +## [2.8.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.2...libp2p-v2.8.3) (2025-04-09) + + +### Bug Fixes + +* handle dialing /p2p/Qmfoo-style addresses ([#3064](https://github.com/libp2p/js-libp2p/issues/3064)) ([bec05ed](https://github.com/libp2p/js-libp2p/commit/bec05ed48219f6ed9af4a4a7a13a1b4a462c3cee)) +* update stream deps ([#3055](https://github.com/libp2p/js-libp2p/issues/3055)) ([b2124c2](https://github.com/libp2p/js-libp2p/commit/b2124c2db02d7870b958f294da42ec79084818a3)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.15 to ^5.1.0 + * @libp2p/interface bumped from ^2.7.0 to ^2.8.0 + * @libp2p/interface-internal bumped from ^2.3.9 to ^2.3.10 + * @libp2p/logger bumped from ^5.1.13 to ^5.1.14 + * @libp2p/multistream-select bumped from ^6.0.20 to ^6.0.21 + * @libp2p/peer-collections bumped from ^6.0.25 to ^6.0.26 + * @libp2p/peer-id bumped from ^5.1.0 to ^5.1.1 + * @libp2p/peer-store bumped from ^11.1.2 to ^11.1.3 + * @libp2p/utils bumped from ^6.6.0 to ^6.6.1 + +## [2.8.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.1...libp2p-v2.8.2) (2025-03-18) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.3.8 to ^2.3.9 + * @libp2p/peer-collections bumped from ^6.0.24 to ^6.0.25 + * @libp2p/peer-store bumped from ^11.1.1 to ^11.1.2 + * @libp2p/utils bumped from ^6.5.8 to ^6.6.0 + +## [2.8.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.8.0...libp2p-v2.8.1) (2025-03-12) + + +### Bug Fixes + +* import StreamHandler from interface ([#3037](https://github.com/libp2p/js-libp2p/issues/3037)) ([88b5c29](https://github.com/libp2p/js-libp2p/commit/88b5c29ed78b54e51c2a69094c8d9f2d41f2287c)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.3.7 to ^2.3.8 + * @libp2p/logger bumped from ^5.1.12 to ^5.1.13 + * @libp2p/multistream-select bumped from ^6.0.19 to ^6.0.20 + * @libp2p/peer-collections bumped from ^6.0.23 to ^6.0.24 + * @libp2p/peer-id bumped from ^5.0.16 to ^5.1.0 + * @libp2p/peer-store bumped from ^11.1.0 to ^11.1.1 + * @libp2p/utils bumped from ^6.5.7 to ^6.5.8 + +## [2.8.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.7.5...libp2p-v2.8.0) (2025-03-03) + + +### Features + +* allow early muxer selection by connection encrypters ([#3022](https://github.com/libp2p/js-libp2p/issues/3022)) ([dd71d8a](https://github.com/libp2p/js-libp2p/commit/dd71d8a86841acbccdca8f3e930bda0eced6d1d0)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.14 to ^5.0.15 + * @libp2p/interface bumped from ^2.6.1 to ^2.7.0 + * @libp2p/interface-internal bumped from ^2.3.6 to ^2.3.7 + * @libp2p/logger bumped from ^5.1.11 to ^5.1.12 + * @libp2p/multistream-select bumped from ^6.0.18 to ^6.0.19 + * @libp2p/peer-collections bumped from ^6.0.22 to ^6.0.23 + * @libp2p/peer-id bumped from ^5.0.15 to ^5.0.16 + * @libp2p/peer-store bumped from ^11.0.22 to ^11.1.0 + * @libp2p/utils bumped from ^6.5.6 to ^6.5.7 + +## [2.7.5](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.7.4...libp2p-v2.7.5) (2025-03-03) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.13 to ^5.0.14 + * @libp2p/interface-internal bumped from ^2.3.5 to ^2.3.6 + * @libp2p/logger bumped from ^5.1.10 to ^5.1.11 + * @libp2p/multistream-select bumped from ^6.0.17 to ^6.0.18 + * @libp2p/peer-collections bumped from ^6.0.21 to ^6.0.22 + * @libp2p/peer-id bumped from ^5.0.14 to ^5.0.15 + * @libp2p/peer-store bumped from ^11.0.21 to ^11.0.22 + * @libp2p/utils bumped from ^6.5.5 to ^6.5.6 + +## [2.7.4](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.7.3...libp2p-v2.7.4) (2025-02-26) + + +### Bug Fixes + +* check for new addresses during dialing ([#3003](https://github.com/libp2p/js-libp2p/issues/3003)) ([be9b6a0](https://github.com/libp2p/js-libp2p/commit/be9b6a0708b82f97da00d1e94d74f38314cf1f4f)) +* ignore failures to listen on IPv6 addresses when IPv4 succeeds ([#3001](https://github.com/libp2p/js-libp2p/issues/3001)) ([e2f4943](https://github.com/libp2p/js-libp2p/commit/e2f49432b58fe3f8484c8f7f0237f996b4d211fa)), closes [#2977](https://github.com/libp2p/js-libp2p/issues/2977) +* improve error message when starting server ([#3008](https://github.com/libp2p/js-libp2p/issues/3008)) ([ab1bb86](https://github.com/libp2p/js-libp2p/commit/ab1bb862f3c22059c8d3c7f750ceab0755a0a0f2)) + +## [2.7.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.7.2...libp2p-v2.7.3) (2025-02-25) + + +### Bug Fixes + +* ensure that the upgrader applies timeouts to incoming dials ([#3000](https://github.com/libp2p/js-libp2p/issues/3000)) ([90cca82](https://github.com/libp2p/js-libp2p/commit/90cca822b4cb112fc71bf9ad954023de685a9040)) + + +### Documentation + +* add spellcheck to gh actions ([#2994](https://github.com/libp2p/js-libp2p/issues/2994)) ([5b084e9](https://github.com/libp2p/js-libp2p/commit/5b084e9682a572e82f7907714d7807b3b9856326)) +* update spell check ([#2999](https://github.com/libp2p/js-libp2p/issues/2999)) ([6f8cfea](https://github.com/libp2p/js-libp2p/commit/6f8cfeafb2f6ddc231a85ca369fb33cf759940f7)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.12 to ^5.0.13 + * @libp2p/interface bumped from ^2.6.0 to ^2.6.1 + * @libp2p/interface-internal bumped from ^2.3.4 to ^2.3.5 + * @libp2p/logger bumped from ^5.1.9 to ^5.1.10 + * @libp2p/multistream-select bumped from ^6.0.16 to ^6.0.17 + * @libp2p/peer-collections bumped from ^6.0.20 to ^6.0.21 + * @libp2p/peer-id bumped from ^5.0.13 to ^5.0.14 + * @libp2p/peer-store bumped from ^11.0.20 to ^11.0.21 + * @libp2p/utils bumped from ^6.5.4 to ^6.5.5 + +## [2.7.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.7.1...libp2p-v2.7.2) (2025-02-21) + + +### Bug Fixes + +* report version correctly ([#2984](https://github.com/libp2p/js-libp2p/issues/2984)) ([9b1a379](https://github.com/libp2p/js-libp2p/commit/9b1a3791dc5a37f23d608f222fc6a48f999096a5)) +* update race-signal ([#2986](https://github.com/libp2p/js-libp2p/issues/2986)) ([2a3cec9](https://github.com/libp2p/js-libp2p/commit/2a3cec9220f1250b7558635c4cb37d61f745645d)), closes [#2702](https://github.com/libp2p/js-libp2p/issues/2702) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.3.3 to ^2.3.4 + * @libp2p/multistream-select bumped from ^6.0.15 to ^6.0.16 + * @libp2p/peer-collections bumped from ^6.0.19 to ^6.0.20 + * @libp2p/peer-store bumped from ^11.0.19 to ^11.0.20 + * @libp2p/utils bumped from ^6.5.3 to ^6.5.4 + +## [2.7.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.7.0...libp2p-v2.7.1) (2025-02-21) + + +### Bug Fixes + +* dial loopback addresses last ([#2982](https://github.com/libp2p/js-libp2p/issues/2982)) ([1ab50cc](https://github.com/libp2p/js-libp2p/commit/1ab50cc0d1ce19f629105b9e154be9f8571dba8d)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.3.2 to ^2.3.3 + * @libp2p/peer-collections bumped from ^6.0.18 to ^6.0.19 + * @libp2p/peer-store bumped from ^11.0.18 to ^11.0.19 + * @libp2p/utils bumped from ^6.5.2 to ^6.5.3 + +## [2.7.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.6.3...libp2p-v2.7.0) (2025-02-20) + + +### Features + +* allow transports to modify announce addresses ([#2978](https://github.com/libp2p/js-libp2p/issues/2978)) ([8331c8e](https://github.com/libp2p/js-libp2p/commit/8331c8ea8feef1d642b6667213409dbe8293b606)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.11 to ^5.0.12 + * @libp2p/interface bumped from ^2.5.0 to ^2.6.0 + * @libp2p/interface-internal bumped from ^2.3.1 to ^2.3.2 + * @libp2p/logger bumped from ^5.1.8 to ^5.1.9 + * @libp2p/multistream-select bumped from ^6.0.14 to ^6.0.15 + * @libp2p/peer-collections bumped from ^6.0.17 to ^6.0.18 + * @libp2p/peer-id bumped from ^5.0.12 to ^5.0.13 + * @libp2p/peer-store bumped from ^11.0.17 to ^11.0.18 + * @libp2p/utils bumped from ^6.5.1 to ^6.5.2 + +## [2.6.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.6.2...libp2p-v2.6.3) (2025-02-18) + + +### Dependencies + +* bump it-length-prefixed from 9.1.1 to 10.0.1 ([#2962](https://github.com/libp2p/js-libp2p/issues/2962)) ([1fc0e26](https://github.com/libp2p/js-libp2p/commit/1fc0e26620d2fd9d752179ab4f6dcc7b6ed5ee5c)) +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.3.0 to ^2.3.1 + * @libp2p/multistream-select bumped from ^6.0.13 to ^6.0.14 + +## [2.6.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.6.1...libp2p-v2.6.2) (2025-02-13) + + +### Bug Fixes + +* respect dial signal and expose protocol negotiation timeouts ([#2956](https://github.com/libp2p/js-libp2p/issues/2956)) ([f9345a7](https://github.com/libp2p/js-libp2p/commit/f9345a7a10974edf47a61279360b57012aae2da0)) + +## [2.6.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.6.0...libp2p-v2.6.1) (2025-02-10) + + +### Bug Fixes + +* override user agent in exports map ([#2952](https://github.com/libp2p/js-libp2p/issues/2952)) ([d8f003e](https://github.com/libp2p/js-libp2p/commit/d8f003e6e512fb3cff46ab167e7cd4f521c13f1b)) + +## [2.6.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.5.2...libp2p-v2.6.0) (2025-02-10) + + +### Features + +* allow overriding stream handlers ([#2945](https://github.com/libp2p/js-libp2p/issues/2945)) ([21088c5](https://github.com/libp2p/js-libp2p/commit/21088c5195df2c3c371fc28bb824f5f84760bf12)), closes [#2928](https://github.com/libp2p/js-libp2p/issues/2928) + + +### Bug Fixes + +* include platform in user agent ([#2942](https://github.com/libp2p/js-libp2p/issues/2942)) ([96f14e4](https://github.com/libp2p/js-libp2p/commit/96f14e429eac84d02504c4b97f183511c8af2add)) +* upgrade observed address to ip mapping ([#2941](https://github.com/libp2p/js-libp2p/issues/2941)) ([d795be1](https://github.com/libp2p/js-libp2p/commit/d795be1870c07464d3bc2d1c00823074331c7432)), closes [#2929](https://github.com/libp2p/js-libp2p/issues/2929) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.10 to ^5.0.11 + * @libp2p/interface bumped from ^2.4.1 to ^2.5.0 + * @libp2p/interface-internal bumped from ^2.2.4 to ^2.3.0 + * @libp2p/logger bumped from ^5.1.7 to ^5.1.8 + * @libp2p/multistream-select bumped from ^6.0.12 to ^6.0.13 + * @libp2p/peer-collections bumped from ^6.0.16 to ^6.0.17 + * @libp2p/peer-id bumped from ^5.0.11 to ^5.0.12 + * @libp2p/peer-store bumped from ^11.0.16 to ^11.0.17 + * @libp2p/utils bumped from ^6.5.0 to ^6.5.1 + +## [2.5.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.5.1...libp2p-v2.5.2) (2025-02-04) + + +### Bug Fixes + +* set expires on observed address ([#2935](https://github.com/libp2p/js-libp2p/issues/2935)) ([d61cbac](https://github.com/libp2p/js-libp2p/commit/d61cbacec14b9cdc61984d3b9e67f20eec038c4e)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.2.3 to ^2.2.4 + * @libp2p/peer-collections bumped from ^6.0.15 to ^6.0.16 + * @libp2p/peer-store bumped from ^11.0.15 to ^11.0.16 + * @libp2p/utils bumped from ^6.4.0 to ^6.5.0 + +## [2.5.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.5.0...libp2p-v2.5.1) (2025-02-03) + + +### Bug Fixes + +* allow overriding mss mode ([#2924](https://github.com/libp2p/js-libp2p/issues/2924)) ([4bbcfa7](https://github.com/libp2p/js-libp2p/commit/4bbcfa707bba45a028429061ce44dec3dd7add34)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.9 to ^5.0.10 + * @libp2p/interface bumped from ^2.4.0 to ^2.4.1 + * @libp2p/interface-internal bumped from ^2.2.2 to ^2.2.3 + * @libp2p/logger bumped from ^5.1.6 to ^5.1.7 + * @libp2p/multistream-select bumped from ^6.0.11 to ^6.0.12 + * @libp2p/peer-collections bumped from ^6.0.14 to ^6.0.15 + * @libp2p/peer-id bumped from ^5.0.10 to ^5.0.11 + * @libp2p/peer-store bumped from ^11.0.14 to ^11.0.15 + * @libp2p/utils bumped from ^6.3.1 to ^6.4.0 + +## [2.5.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.4.2...libp2p-v2.5.0) (2025-01-07) + + +### Features + +* add traceFunction call to metrics ([#2898](https://github.com/libp2p/js-libp2p/issues/2898)) ([20d9ba7](https://github.com/libp2p/js-libp2p/commit/20d9ba73e2fc76e42327458b2a1e29d1ba162bba)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.8 to ^5.0.9 + * @libp2p/interface bumped from ^2.3.0 to ^2.4.0 + * @libp2p/interface-internal bumped from ^2.2.1 to ^2.2.2 + * @libp2p/logger bumped from ^5.1.5 to ^5.1.6 + * @libp2p/multistream-select bumped from ^6.0.10 to ^6.0.11 + * @libp2p/peer-collections bumped from ^6.0.13 to ^6.0.14 + * @libp2p/peer-id bumped from ^5.0.9 to ^5.0.10 + * @libp2p/peer-store bumped from ^11.0.13 to ^11.0.14 + * @libp2p/utils bumped from ^6.3.0 to ^6.3.1 + +## [2.4.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.4.1...libp2p-v2.4.2) (2024-12-12) + + +### Bug Fixes + +* pass abort signal to peer routing query ([#2888](https://github.com/libp2p/js-libp2p/issues/2888)) ([3c63482](https://github.com/libp2p/js-libp2p/commit/3c63482e5587e0edabb5c215cb6e565ed4f1185e)) + +## [2.4.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.4.0...libp2p-v2.4.1) (2024-12-10) + + +### Bug Fixes + +* auto-confirm relay addresses ([#2886](https://github.com/libp2p/js-libp2p/issues/2886)) ([5c4a79e](https://github.com/libp2p/js-libp2p/commit/5c4a79e5a6e8d0db1ef6464075841a0b9de507ef)), closes [#2883](https://github.com/libp2p/js-libp2p/issues/2883) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.2.0 to ^2.2.1 + +## [2.4.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.3.1...libp2p-v2.4.0) (2024-12-09) + + +### Features + +* add append announce addresses ([#2834](https://github.com/libp2p/js-libp2p/issues/2834)) ([b248eef](https://github.com/libp2p/js-libp2p/commit/b248eefc01e6034c211b0d458d0ce7a74e99c24f)) +* allow adding external ip/port mapping ([#2836](https://github.com/libp2p/js-libp2p/issues/2836)) ([6ddc1b8](https://github.com/libp2p/js-libp2p/commit/6ddc1b80ebe396afee58082865ae6cae2bb39fb1)) +* Use CIDR format for connection-manager allow/deny lists ([#2783](https://github.com/libp2p/js-libp2p/issues/2783)) ([48e9cfa](https://github.com/libp2p/js-libp2p/commit/48e9cfa56fdf9d2dcdc0efc758cf7f055106cbb5)) + + +### Bug Fixes + +* confirm dns mappings with ip mappings ([#2861](https://github.com/libp2p/js-libp2p/issues/2861)) ([0f87479](https://github.com/libp2p/js-libp2p/commit/0f8747950c26a47828c826b7f0a257bf95276b0f)) +* ensure user dial signals are respected ([#2842](https://github.com/libp2p/js-libp2p/issues/2842)) ([bc90b4f](https://github.com/libp2p/js-libp2p/commit/bc90b4fd58aee1ccd94d4fd61cc48d336e77d772)) +* handle router mappings of mixed IP version ([#2858](https://github.com/libp2p/js-libp2p/issues/2858)) ([f28c31d](https://github.com/libp2p/js-libp2p/commit/f28c31d803f13872ec151f8b5fe073aedc5dbcbf)) +* limit observed addresses in address manager ([#2869](https://github.com/libp2p/js-libp2p/issues/2869)) ([06f79b6](https://github.com/libp2p/js-libp2p/commit/06f79b6466fa8f6656676a71a5b90e6071825303)) +* remove browser dial filter ([#2838](https://github.com/libp2p/js-libp2p/issues/2838)) ([d6cd25d](https://github.com/libp2p/js-libp2p/commit/d6cd25d0deca292420093d894edbfbc47b347e5d)) +* require confirmation of global unicast addresses ([#2876](https://github.com/libp2p/js-libp2p/issues/2876)) ([92cc740](https://github.com/libp2p/js-libp2p/commit/92cc740828963a4786ea83befe606dac4ba25e45)) +* require external confirmation of public addresses ([#2867](https://github.com/libp2p/js-libp2p/issues/2867)) ([d19974d](https://github.com/libp2p/js-libp2p/commit/d19974d93a1015acfca95c2155dbcffc5fd6a6c0)) +* trigger self:peer:update when ip/dns mappings change ([#2839](https://github.com/libp2p/js-libp2p/issues/2839)) ([4a85eb0](https://github.com/libp2p/js-libp2p/commit/4a85eb033f7ea8461a10bc8b38bbc76d1383d1cc)) +* update agent version ([#2845](https://github.com/libp2p/js-libp2p/issues/2845)) ([4761dd7](https://github.com/libp2p/js-libp2p/commit/4761dd701aec6620ee504cb9908fa2319971b79b)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.7 to ^5.0.8 + * @libp2p/interface bumped from ^2.2.1 to ^2.3.0 + * @libp2p/interface-internal bumped from ^2.1.1 to ^2.2.0 + * @libp2p/logger bumped from ^5.1.4 to ^5.1.5 + * @libp2p/multistream-select bumped from ^6.0.9 to ^6.0.10 + * @libp2p/peer-collections bumped from ^6.0.12 to ^6.0.13 + * @libp2p/peer-id bumped from ^5.0.8 to ^5.0.9 + * @libp2p/peer-store bumped from ^11.0.12 to ^11.0.13 + * @libp2p/utils bumped from ^6.2.1 to ^6.3.0 + +## [2.3.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.3.0...libp2p-v2.3.1) (2024-11-18) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.6 to ^5.0.7 + * @libp2p/interface bumped from ^2.2.0 to ^2.2.1 + * @libp2p/interface-internal bumped from ^2.1.0 to ^2.1.1 + * @libp2p/logger bumped from ^5.1.3 to ^5.1.4 + * @libp2p/multistream-select bumped from ^6.0.8 to ^6.0.9 + * @libp2p/peer-collections bumped from ^6.0.11 to ^6.0.12 + * @libp2p/peer-id bumped from ^5.0.7 to ^5.0.8 + * @libp2p/peer-store bumped from ^11.0.11 to ^11.0.12 + * @libp2p/utils bumped from ^6.2.0 to ^6.2.1 + +## [2.3.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.2.1...libp2p-v2.3.0) (2024-11-16) + + +### Features + +* add dns mappings to address manager ([#2818](https://github.com/libp2p/js-libp2p/issues/2818)) ([7dcabb8](https://github.com/libp2p/js-libp2p/commit/7dcabb884c37dfba69e3ce427544ab05209d137b)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.0.10 to ^2.1.0 + * @libp2p/peer-collections bumped from ^6.0.10 to ^6.0.11 + * @libp2p/peer-store bumped from ^11.0.10 to ^11.0.11 + * @libp2p/utils bumped from ^6.1.3 to ^6.2.0 + +## [2.2.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.2.0...libp2p-v2.2.1) (2024-10-28) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/websockets bumped from ^9.0.10 to ^9.0.11 + +## [2.2.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.10...libp2p-v2.2.0) (2024-10-28) + + +### Features + +* add reprovide ([#2785](https://github.com/libp2p/js-libp2p/issues/2785)) ([52b3b1a](https://github.com/libp2p/js-libp2p/commit/52b3b1a16e56f73de9a75e7f62d5c3b367d757d9)) + + +### Bug Fixes + +* only update pending incoming connections if connection accepted ([#2790](https://github.com/libp2p/js-libp2p/issues/2790)) ([d34642d](https://github.com/libp2p/js-libp2p/commit/d34642db1c2be39a74fe7cf21508eb17c19c8a22)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.5 to ^5.0.6 + * @libp2p/interface bumped from ^2.1.3 to ^2.2.0 + * @libp2p/interface-internal bumped from ^2.0.9 to ^2.0.10 + * @libp2p/logger bumped from ^5.1.2 to ^5.1.3 + * @libp2p/multistream-select bumped from ^6.0.7 to ^6.0.8 + * @libp2p/peer-collections bumped from ^6.0.9 to ^6.0.10 + * @libp2p/peer-id bumped from ^5.0.6 to ^5.0.7 + * @libp2p/peer-store bumped from ^11.0.9 to ^11.0.10 + * @libp2p/utils bumped from ^6.1.2 to ^6.1.3 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^3.0.0 to ^3.1.0 + * @libp2p/identify bumped from ^3.0.9 to ^3.0.10 + * @libp2p/interface-compliance-tests bumped from ^6.1.7 to ^6.1.8 + * @libp2p/mplex bumped from ^11.0.9 to ^11.0.10 + * @libp2p/plaintext bumped from ^2.0.9 to ^2.0.10 + * @libp2p/tcp bumped from ^10.0.10 to ^10.0.11 + * @libp2p/websockets bumped from ^9.0.9 to ^9.0.10 + +## [2.1.10](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.9...libp2p-v2.1.10) (2024-10-23) + + +### Documentation + +* add roadmap for 2024/early 25 ([#2754](https://github.com/libp2p/js-libp2p/issues/2754)) ([3bc9769](https://github.com/libp2p/js-libp2p/commit/3bc9769b8aff1e9bb3588905323a2bc6b7d7b7bf)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.0.8 to ^2.0.9 + * @libp2p/logger bumped from ^5.1.1 to ^5.1.2 + * @libp2p/multistream-select bumped from ^6.0.6 to ^6.0.7 + * @libp2p/peer-collections bumped from ^6.0.8 to ^6.0.9 + * @libp2p/peer-id bumped from ^5.0.5 to ^5.0.6 + * @libp2p/peer-store bumped from ^11.0.8 to ^11.0.9 + * @libp2p/utils bumped from ^6.1.1 to ^6.1.2 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.1.5 to ^3.0.0 + * @libp2p/identify bumped from ^3.0.8 to ^3.0.9 + * @libp2p/interface-compliance-tests bumped from ^6.1.6 to ^6.1.7 + * @libp2p/mplex bumped from ^11.0.8 to ^11.0.9 + * @libp2p/plaintext bumped from ^2.0.8 to ^2.0.9 + * @libp2p/tcp bumped from ^10.0.9 to ^10.0.10 + * @libp2p/websockets bumped from ^9.0.8 to ^9.0.9 + +## [2.1.9](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.8...libp2p-v2.1.9) (2024-10-11) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.1.4 to ^2.1.5 + +## [2.1.8](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.7...libp2p-v2.1.8) (2024-10-09) + + +### Bug Fixes + +* emit 'listening' when relays change ([#2758](https://github.com/libp2p/js-libp2p/issues/2758)) ([0d326d1](https://github.com/libp2p/js-libp2p/commit/0d326d102e4f6bf06c6f3e961a3b6b5844486495)) +* use keep-alive as a tag prefix ([#2757](https://github.com/libp2p/js-libp2p/issues/2757)) ([29b47ad](https://github.com/libp2p/js-libp2p/commit/29b47adb47b48e9a2b01580bd0d50dc7c2be8fd6)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.4 to ^5.0.5 + * @libp2p/interface bumped from ^2.1.2 to ^2.1.3 + * @libp2p/interface-internal bumped from ^2.0.7 to ^2.0.8 + * @libp2p/logger bumped from ^5.1.0 to ^5.1.1 + * @libp2p/multistream-select bumped from ^6.0.5 to ^6.0.6 + * @libp2p/peer-collections bumped from ^6.0.7 to ^6.0.8 + * @libp2p/peer-id bumped from ^5.0.4 to ^5.0.5 + * @libp2p/peer-store bumped from ^11.0.7 to ^11.0.8 + * @libp2p/utils bumped from ^6.1.0 to ^6.1.1 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.1.3 to ^2.1.4 + * @libp2p/identify bumped from ^3.0.7 to ^3.0.8 + * @libp2p/interface-compliance-tests bumped from ^6.1.5 to ^6.1.6 + * @libp2p/mplex bumped from ^11.0.7 to ^11.0.8 + * @libp2p/plaintext bumped from ^2.0.7 to ^2.0.8 + * @libp2p/tcp bumped from ^10.0.8 to ^10.0.9 + * @libp2p/websockets bumped from ^9.0.7 to ^9.0.8 + +## [2.1.7](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.6...libp2p-v2.1.7) (2024-10-09) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.1.2 to ^2.1.3 + +## [2.1.6](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.5...libp2p-v2.1.6) (2024-10-05) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.0.6 to ^2.0.7 + * @libp2p/peer-collections bumped from ^6.0.6 to ^6.0.7 + * @libp2p/peer-store bumped from ^11.0.6 to ^11.0.7 + * @libp2p/utils bumped from ^6.0.6 to ^6.1.0 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.1.1 to ^2.1.2 + * @libp2p/identify bumped from ^3.0.6 to ^3.0.7 + * @libp2p/interface-compliance-tests bumped from ^6.1.4 to ^6.1.5 + * @libp2p/mplex bumped from ^11.0.6 to ^11.0.7 + * @libp2p/plaintext bumped from ^2.0.6 to ^2.0.7 + * @libp2p/tcp bumped from ^10.0.7 to ^10.0.8 + * @libp2p/websockets bumped from ^9.0.6 to ^9.0.7 + +## [2.1.5](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.4...libp2p-v2.1.5) (2024-09-30) + + +### Bug Fixes + +* record outbound pending connections metric ([#2737](https://github.com/libp2p/js-libp2p/issues/2737)) ([d9c7e0f](https://github.com/libp2p/js-libp2p/commit/d9c7e0f7ec608bd5154f30ae7baa6f1d6020bdfc)) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/tcp bumped from ^10.0.6 to ^10.0.7 + +## [2.1.4](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.3...libp2p-v2.1.4) (2024-09-27) + + +### Bug Fixes + +* check for connection status before storing ([#2732](https://github.com/libp2p/js-libp2p/issues/2732)) ([7e4e6bd](https://github.com/libp2p/js-libp2p/commit/7e4e6bdbf3e735c4cffba7a398a50aa0664ae480)) +* sort addresses by transport before dial ([#2731](https://github.com/libp2p/js-libp2p/issues/2731)) ([dad979f](https://github.com/libp2p/js-libp2p/commit/dad979f9bf1181defb1a72de69b21f5b8d7fce5b)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.0.5 to ^2.0.6 + * @libp2p/peer-collections bumped from ^6.0.5 to ^6.0.6 + * @libp2p/peer-store bumped from ^11.0.5 to ^11.0.6 + * @libp2p/utils bumped from ^6.0.5 to ^6.0.6 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.1.0 to ^2.1.1 + * @libp2p/identify bumped from ^3.0.5 to ^3.0.6 + * @libp2p/interface-compliance-tests bumped from ^6.1.3 to ^6.1.4 + * @libp2p/mplex bumped from ^11.0.5 to ^11.0.6 + * @libp2p/plaintext bumped from ^2.0.5 to ^2.0.6 + * @libp2p/tcp bumped from ^10.0.5 to ^10.0.6 + * @libp2p/websockets bumped from ^9.0.5 to ^9.0.6 + +## [2.1.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.2...libp2p-v2.1.3) (2024-09-25) + + +### Bug Fixes + +* split error/operation metrics ([#2728](https://github.com/libp2p/js-libp2p/issues/2728)) ([0c59578](https://github.com/libp2p/js-libp2p/commit/0c5957836d1416566f18233f58c92e7db6ab5525)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^2.0.4 to ^2.0.5 + * @libp2p/logger bumped from ^5.0.4 to ^5.1.0 + * @libp2p/multistream-select bumped from ^6.0.4 to ^6.0.5 + * @libp2p/peer-collections bumped from ^6.0.4 to ^6.0.5 + * @libp2p/peer-store bumped from ^11.0.4 to ^11.0.5 + * @libp2p/utils bumped from ^6.0.4 to ^6.0.5 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.0.4 to ^2.1.0 + * @libp2p/identify bumped from ^3.0.4 to ^3.0.5 + * @libp2p/interface-compliance-tests bumped from ^6.1.2 to ^6.1.3 + * @libp2p/mplex bumped from ^11.0.4 to ^11.0.5 + * @libp2p/plaintext bumped from ^2.0.4 to ^2.0.5 + * @libp2p/tcp bumped from ^10.0.4 to ^10.0.5 + * @libp2p/websockets bumped from ^9.0.4 to ^9.0.5 + +## [2.1.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.1...libp2p-v2.1.2) (2024-09-24) + + +### Bug Fixes + +* simplify connection upgrade ([#2719](https://github.com/libp2p/js-libp2p/issues/2719)) ([c258b35](https://github.com/libp2p/js-libp2p/commit/c258b35af60eec906437129ab31201bfb9c80d16)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.3 to ^5.0.4 + * @libp2p/interface bumped from ^2.1.1 to ^2.1.2 + * @libp2p/interface-internal bumped from ^2.0.3 to ^2.0.4 + * @libp2p/logger bumped from ^5.0.3 to ^5.0.4 + * @libp2p/multistream-select bumped from ^6.0.3 to ^6.0.4 + * @libp2p/peer-collections bumped from ^6.0.3 to ^6.0.4 + * @libp2p/peer-id bumped from ^5.0.3 to ^5.0.4 + * @libp2p/peer-store bumped from ^11.0.3 to ^11.0.4 + * @libp2p/utils bumped from ^6.0.3 to ^6.0.4 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.0.3 to ^2.0.4 + * @libp2p/identify bumped from ^3.0.3 to ^3.0.4 + * @libp2p/interface-compliance-tests bumped from ^6.1.1 to ^6.1.2 + * @libp2p/mplex bumped from ^11.0.3 to ^11.0.4 + * @libp2p/plaintext bumped from ^2.0.3 to ^2.0.4 + * @libp2p/tcp bumped from ^10.0.3 to ^10.0.4 + * @libp2p/websockets bumped from ^9.0.3 to ^9.0.4 + +## [2.1.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.1.0...libp2p-v2.1.1) (2024-09-24) + + +### Bug Fixes + +* export transiently referenced types ([#2717](https://github.com/libp2p/js-libp2p/issues/2717)) ([7f7ec82](https://github.com/libp2p/js-libp2p/commit/7f7ec82ae4ee7761360bdfdd294de271feaf1841)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.2 to ^5.0.3 + * @libp2p/interface bumped from ^2.1.0 to ^2.1.1 + * @libp2p/interface-internal bumped from ^2.0.2 to ^2.0.3 + * @libp2p/logger bumped from ^5.0.2 to ^5.0.3 + * @libp2p/multistream-select bumped from ^6.0.2 to ^6.0.3 + * @libp2p/peer-collections bumped from ^6.0.2 to ^6.0.3 + * @libp2p/peer-id bumped from ^5.0.2 to ^5.0.3 + * @libp2p/peer-store bumped from ^11.0.2 to ^11.0.3 + * @libp2p/utils bumped from ^6.0.2 to ^6.0.3 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.0.2 to ^2.0.3 + * @libp2p/identify bumped from ^3.0.2 to ^3.0.3 + * @libp2p/interface-compliance-tests bumped from ^6.1.0 to ^6.1.1 + * @libp2p/mplex bumped from ^11.0.2 to ^11.0.3 + * @libp2p/plaintext bumped from ^2.0.2 to ^2.0.3 + * @libp2p/tcp bumped from ^10.0.2 to ^10.0.3 + * @libp2p/websockets bumped from ^9.0.2 to ^9.0.3 + +## [2.1.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.0.3...libp2p-v2.1.0) (2024-09-24) + + +### Features + +* add pending connections count to metrics ([#2713](https://github.com/libp2p/js-libp2p/issues/2713)) ([b3272cf](https://github.com/libp2p/js-libp2p/commit/b3272cfce13a56ea2302e5a6fe5dd0743c109cf7)) + +## [2.0.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.0.2...libp2p-v2.0.3) (2024-09-23) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.1 to ^5.0.2 + * @libp2p/interface bumped from ^2.0.1 to ^2.1.0 + * @libp2p/interface-internal bumped from ^2.0.1 to ^2.0.2 + * @libp2p/logger bumped from ^5.0.1 to ^5.0.2 + * @libp2p/multistream-select bumped from ^6.0.1 to ^6.0.2 + * @libp2p/peer-collections bumped from ^6.0.1 to ^6.0.2 + * @libp2p/peer-id bumped from ^5.0.1 to ^5.0.2 + * @libp2p/peer-store bumped from ^11.0.1 to ^11.0.2 + * @libp2p/utils bumped from ^6.0.1 to ^6.0.2 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.0.1 to ^2.0.2 + * @libp2p/identify bumped from ^3.0.1 to ^3.0.2 + * @libp2p/interface-compliance-tests bumped from ^6.0.1 to ^6.1.0 + * @libp2p/mplex bumped from ^11.0.1 to ^11.0.2 + * @libp2p/plaintext bumped from ^2.0.1 to ^2.0.2 + * @libp2p/tcp bumped from ^10.0.1 to ^10.0.2 + * @libp2p/websockets bumped from ^9.0.1 to ^9.0.2 + +## [2.0.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.0.1...libp2p-v2.0.2) (2024-09-12) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^5.0.0 to ^5.0.1 + * @libp2p/interface bumped from ^2.0.0 to ^2.0.1 + * @libp2p/interface-internal bumped from ^2.0.0 to ^2.0.1 + * @libp2p/logger bumped from ^5.0.0 to ^5.0.1 + * @libp2p/multistream-select bumped from ^6.0.0 to ^6.0.1 + * @libp2p/peer-collections bumped from ^6.0.0 to ^6.0.1 + * @libp2p/peer-id bumped from ^5.0.0 to ^5.0.1 + * @libp2p/peer-store bumped from ^11.0.0 to ^11.0.1 + * @libp2p/utils bumped from ^6.0.0 to ^6.0.1 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^2.0.0 to ^2.0.1 + * @libp2p/identify bumped from ^3.0.0 to ^3.0.1 + * @libp2p/interface-compliance-tests bumped from ^6.0.0 to ^6.0.1 + * @libp2p/mplex bumped from ^11.0.0 to ^11.0.1 + * @libp2p/plaintext bumped from ^2.0.0 to ^2.0.1 + * @libp2p/tcp bumped from ^10.0.0 to ^10.0.1 + * @libp2p/websockets bumped from ^9.0.0 to ^9.0.1 + +## [2.0.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v2.0.0...libp2p-v2.0.1) (2024-09-11) + + +### Bug Fixes + +* remove patches for gossipsub, noise and the daemon modules ([#2694](https://github.com/libp2p/js-libp2p/issues/2694)) ([7cd9845](https://github.com/libp2p/js-libp2p/commit/7cd984569dbf0046861ec84e8e030ef62725fd14)) + +## [2.0.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.9.4...libp2p-v2.0.0) (2024-09-11) + + +### ⚠ BREAKING CHANGES + +* the `connectionEncryption` option has been renamed `connectionEncrypters` +* instead of `CodeError`, use `TimeoutError`, `UnexpectedPeerError`, etc +* - `@libp2p/peer-id-factory` has been removed, use `generateKeyPair` and `peerIdFromPrivateKey` instead +* the final argument to `secureOutbound` and `secureInbound` in the `ConnectionEncrypter` interface is now an options object +* the autodialer has been removed as well as the corresponding config keys +* The `.code` property has been removed from most errors, use `.name` instead +* removes `localPeer: PeerId` first parameter from `secureInbound` and `secureOutbound` in `ConnectionEncrypter` +* * The `notifyOnTransient` property of `libp2p.register` has been renamed `notifyOnLimitedConnection` +* `@libp2p/interface` no longer exports a `CustomEvent` polyfill + +### Features + +* use `.name` property instead of `.code` for errors ([#2655](https://github.com/libp2p/js-libp2p/issues/2655)) ([0d20426](https://github.com/libp2p/js-libp2p/commit/0d20426fd5ea19b03345c70289bbd692e4348e1f)) + + +### Bug Fixes + +* abort connection only when abortConnectionOnPingFailure is true ([#2684](https://github.com/libp2p/js-libp2p/issues/2684)) ([2022036](https://github.com/libp2p/js-libp2p/commit/2022036dfcbbd32289beac28f2fa4c1810f39f2b)) +* make connection securing abortable ([#2662](https://github.com/libp2p/js-libp2p/issues/2662)) ([51f7b57](https://github.com/libp2p/js-libp2p/commit/51f7b570c3a5bae8dd7da7edbc4145893328400e)) +* remove autodialer ([#2639](https://github.com/libp2p/js-libp2p/issues/2639)) ([ab90179](https://github.com/libp2p/js-libp2p/commit/ab901790810d8ce59724af1706c9a9e74341b8ee)) +* remove CodeError class ([#2688](https://github.com/libp2p/js-libp2p/issues/2688)) ([81ebe4e](https://github.com/libp2p/js-libp2p/commit/81ebe4e47e82508a847bb3af0af36cc249b78765)) +* remove CustomEvent export from `@libp2p/interface` ([#2656](https://github.com/libp2p/js-libp2p/issues/2656)) ([fab6fc9](https://github.com/libp2p/js-libp2p/commit/fab6fc960b6bc03a6bc00ae5a4b3551d7d080c73)) +* remove localPeer from secureInbound and secureOutbound ([#2304](https://github.com/libp2p/js-libp2p/issues/2304)) ([b435a21](https://github.com/libp2p/js-libp2p/commit/b435a214cf342c6015f474d26143fc27f0f673e9)) +* remove private key field from peer id ([#2660](https://github.com/libp2p/js-libp2p/issues/2660)) ([3eeb0c7](https://github.com/libp2p/js-libp2p/commit/3eeb0c705bd58285a6e1ec9fcbb6987c5959d504)), closes [#2659](https://github.com/libp2p/js-libp2p/issues/2659) +* rename "transient" connections to "limited" ([#2645](https://github.com/libp2p/js-libp2p/issues/2645)) ([2988602](https://github.com/libp2p/js-libp2p/commit/29886022eddc8a793217b2c888beac8aef63f1be)), closes [#2622](https://github.com/libp2p/js-libp2p/issues/2622) +* rename connectionEncryption option to connectionEncrypters ([#2691](https://github.com/libp2p/js-libp2p/issues/2691)) ([6d72709](https://github.com/libp2p/js-libp2p/commit/6d72709ba5959388777610e2f71b8ba9522139b6)) + + +### Documentation + +* remove mplex from docs ([b6681bd](https://github.com/libp2p/js-libp2p/commit/b6681bd2505ac2749192042c3f16b14a88a8656d)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.9 to ^5.0.0 + * @libp2p/interface bumped from ^1.7.0 to ^2.0.0 + * @libp2p/interface-internal bumped from ^1.3.4 to ^2.0.0 + * @libp2p/logger bumped from ^4.0.20 to ^5.0.0 + * @libp2p/multistream-select bumped from ^5.1.17 to ^6.0.0 + * @libp2p/peer-collections bumped from ^5.2.9 to ^6.0.0 + * @libp2p/peer-id bumped from ^4.2.4 to ^5.0.0 + * @libp2p/peer-store bumped from ^10.1.5 to ^11.0.0 + * @libp2p/utils bumped from ^5.4.9 to ^6.0.0 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.1.5 to ^2.0.0 + * @libp2p/identify bumped from ^2.1.5 to ^3.0.0 + * @libp2p/interface-compliance-tests bumped from ^5.4.12 to ^6.0.0 + * @libp2p/mplex bumped from ^10.1.5 to ^11.0.0 + * @libp2p/plaintext bumped from ^1.1.6 to ^2.0.0 + * @libp2p/tcp bumped from ^9.1.6 to ^10.0.0 + * @libp2p/websockets bumped from ^8.2.0 to ^9.0.0 + +## [1.9.4](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.9.3...libp2p-v1.9.4) (2024-09-05) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/tcp bumped from ^9.1.5 to ^9.1.6 + +## [1.9.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.9.2...libp2p-v1.9.3) (2024-08-29) + + +### Bug Fixes + +* connection monitor compatible with other ping implementations ([#2671](https://github.com/libp2p/js-libp2p/issues/2671)) ([7655e52](https://github.com/libp2p/js-libp2p/commit/7655e5200d32e7fe59387cedacb0fe640e260f1e)) + +## [1.9.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.9.1...libp2p-v1.9.2) (2024-08-17) + + +### Bug Fixes + +* accept custom ping protocol prefix in connection monitor ([#2667](https://github.com/libp2p/js-libp2p/issues/2667)) ([3c8dd5b](https://github.com/libp2p/js-libp2p/commit/3c8dd5bbfc57489a0b10b555c81e773058a58156)) + +## [1.9.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.9.0...libp2p-v1.9.1) (2024-08-16) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/plaintext bumped from ^1.1.5 to ^1.1.6 + +## [1.9.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.8.3...libp2p-v1.9.0) (2024-08-15) + + +### Features + +* add connection monitor ([#2644](https://github.com/libp2p/js-libp2p/issues/2644)) ([7939dbd](https://github.com/libp2p/js-libp2p/commit/7939dbd5cbab1c7b4be671ff976d0258e9b48178)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.8 to ^4.1.9 + * @libp2p/interface bumped from ^1.6.3 to ^1.7.0 + * @libp2p/interface-internal bumped from ^1.3.3 to ^1.3.4 + * @libp2p/logger bumped from ^4.0.19 to ^4.0.20 + * @libp2p/multistream-select bumped from ^5.1.16 to ^5.1.17 + * @libp2p/peer-collections bumped from ^5.2.8 to ^5.2.9 + * @libp2p/peer-id bumped from ^4.2.3 to ^4.2.4 + * @libp2p/peer-id-factory bumped from ^4.2.3 to ^4.2.4 + * @libp2p/peer-store bumped from ^10.1.4 to ^10.1.5 + * @libp2p/utils bumped from ^5.4.8 to ^5.4.9 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.1.4 to ^1.1.5 + * @libp2p/identify bumped from ^2.1.4 to ^2.1.5 + * @libp2p/interface-compliance-tests bumped from ^5.4.11 to ^5.4.12 + * @libp2p/mplex bumped from ^10.1.4 to ^10.1.5 + * @libp2p/plaintext bumped from ^1.1.4 to ^1.1.5 + * @libp2p/tcp bumped from ^9.1.4 to ^9.1.5 + * @libp2p/websockets bumped from ^8.1.4 to ^8.2.0 + +## [1.8.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.8.2...libp2p-v1.8.3) (2024-08-02) + + +### Dependencies + +* bump aegir from 43.0.3 to 44.0.1 ([#2603](https://github.com/libp2p/js-libp2p/issues/2603)) ([944935f](https://github.com/libp2p/js-libp2p/commit/944935f8dbcc1083e4cb4a02b49a0aab3083d3d9)) +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.7 to ^4.1.8 + * @libp2p/interface bumped from ^1.6.2 to ^1.6.3 + * @libp2p/interface-internal bumped from ^1.3.2 to ^1.3.3 + * @libp2p/logger bumped from ^4.0.18 to ^4.0.19 + * @libp2p/multistream-select bumped from ^5.1.15 to ^5.1.16 + * @libp2p/peer-collections bumped from ^5.2.7 to ^5.2.8 + * @libp2p/peer-id bumped from ^4.2.2 to ^4.2.3 + * @libp2p/peer-id-factory bumped from ^4.2.2 to ^4.2.3 + * @libp2p/peer-store bumped from ^10.1.3 to ^10.1.4 + * @libp2p/utils bumped from ^5.4.7 to ^5.4.8 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.1.3 to ^1.1.4 + * @libp2p/identify bumped from ^2.1.3 to ^2.1.4 + * @libp2p/interface-compliance-tests bumped from ^5.4.10 to ^5.4.11 + * @libp2p/mplex bumped from ^10.1.3 to ^10.1.4 + * @libp2p/plaintext bumped from ^1.1.3 to ^1.1.4 + * @libp2p/tcp bumped from ^9.1.3 to ^9.1.4 + * @libp2p/websockets bumped from ^8.1.3 to ^8.1.4 + +## [1.8.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.8.1...libp2p-v1.8.2) (2024-07-29) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.6 to ^4.1.7 + * @libp2p/interface bumped from ^1.6.1 to ^1.6.2 + * @libp2p/interface-internal bumped from ^1.3.1 to ^1.3.2 + * @libp2p/logger bumped from ^4.0.17 to ^4.0.18 + * @libp2p/multistream-select bumped from ^5.1.14 to ^5.1.15 + * @libp2p/peer-collections bumped from ^5.2.6 to ^5.2.7 + * @libp2p/peer-id bumped from ^4.2.1 to ^4.2.2 + * @libp2p/peer-id-factory bumped from ^4.2.1 to ^4.2.2 + * @libp2p/peer-store bumped from ^10.1.2 to ^10.1.3 + * @libp2p/utils bumped from ^5.4.6 to ^5.4.7 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.1.2 to ^1.1.3 + * @libp2p/identify bumped from ^2.1.2 to ^2.1.3 + * @libp2p/interface-compliance-tests bumped from ^5.4.9 to ^5.4.10 + * @libp2p/mplex bumped from ^10.1.2 to ^10.1.3 + * @libp2p/plaintext bumped from ^1.1.2 to ^1.1.3 + * @libp2p/tcp bumped from ^9.1.2 to ^9.1.3 + * @libp2p/websockets bumped from ^8.1.2 to ^8.1.3 + +## [1.8.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.8.0...libp2p-v1.8.1) (2024-07-13) + + +### Bug Fixes + +* expose progress events in dial/dialProtocol types ([#2614](https://github.com/libp2p/js-libp2p/issues/2614)) ([e1f0b30](https://github.com/libp2p/js-libp2p/commit/e1f0b307c6992414d39cd5b44cf971d30f079fab)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.5 to ^4.1.6 + * @libp2p/interface bumped from ^1.6.0 to ^1.6.1 + * @libp2p/interface-internal bumped from ^1.3.0 to ^1.3.1 + * @libp2p/logger bumped from ^4.0.16 to ^4.0.17 + * @libp2p/multistream-select bumped from ^5.1.13 to ^5.1.14 + * @libp2p/peer-collections bumped from ^5.2.5 to ^5.2.6 + * @libp2p/peer-id bumped from ^4.2.0 to ^4.2.1 + * @libp2p/peer-id-factory bumped from ^4.2.0 to ^4.2.1 + * @libp2p/peer-store bumped from ^10.1.1 to ^10.1.2 + * @libp2p/utils bumped from ^5.4.5 to ^5.4.6 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.1.1 to ^1.1.2 + * @libp2p/identify bumped from ^2.1.1 to ^2.1.2 + * @libp2p/interface-compliance-tests bumped from ^5.4.8 to ^5.4.9 + * @libp2p/mplex bumped from ^10.1.1 to ^10.1.2 + * @libp2p/plaintext bumped from ^1.1.1 to ^1.1.2 + * @libp2p/tcp bumped from ^9.1.1 to ^9.1.2 + * @libp2p/websockets bumped from ^8.1.1 to ^8.1.2 + +## [1.8.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.7.0...libp2p-v1.8.0) (2024-07-03) + + +### Features + +* invoke progress events during dialing ([#2596](https://github.com/libp2p/js-libp2p/issues/2596)) ([6573cb8](https://github.com/libp2p/js-libp2p/commit/6573cb8b072c9ab3b0b374a9d2a4270cbc5c19b6)) + + +### Bug Fixes + +* add dial progress events to transports ([#2607](https://github.com/libp2p/js-libp2p/issues/2607)) ([abb9f90](https://github.com/libp2p/js-libp2p/commit/abb9f90c7694ac9ff77b45930304a92b1db428ea)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.4 to ^4.1.5 + * @libp2p/interface bumped from ^1.5.0 to ^1.6.0 + * @libp2p/interface-internal bumped from ^1.2.4 to ^1.3.0 + * @libp2p/logger bumped from ^4.0.15 to ^4.0.16 + * @libp2p/multistream-select bumped from ^5.1.12 to ^5.1.13 + * @libp2p/peer-collections bumped from ^5.2.4 to ^5.2.5 + * @libp2p/peer-id bumped from ^4.1.4 to ^4.2.0 + * @libp2p/peer-id-factory bumped from ^4.1.4 to ^4.2.0 + * @libp2p/peer-store bumped from ^10.1.0 to ^10.1.1 + * @libp2p/utils bumped from ^5.4.4 to ^5.4.5 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.1.0 to ^1.1.1 + * @libp2p/identify bumped from ^2.1.0 to ^2.1.1 + * @libp2p/interface-compliance-tests bumped from ^5.4.7 to ^5.4.8 + * @libp2p/mplex bumped from ^10.1.0 to ^10.1.1 + * @libp2p/plaintext bumped from ^1.1.0 to ^1.1.1 + * @libp2p/tcp bumped from ^9.1.0 to ^9.1.1 + * @libp2p/websockets bumped from ^8.1.0 to ^8.1.1 + +## [1.7.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.6.1...libp2p-v1.7.0) (2024-06-18) + + +### Features + +* check service dependencies on startup ([#2586](https://github.com/libp2p/js-libp2p/issues/2586)) ([d1f1c2b](https://github.com/libp2p/js-libp2p/commit/d1f1c2be78bd195f404e62627c2c9f545845e5f5)) + + +### Bug Fixes + +* allow custom services to depend on each other ([#2588](https://github.com/libp2p/js-libp2p/issues/2588)) ([0447913](https://github.com/libp2p/js-libp2p/commit/044791342239b187d4fdabb957b0ca6af93d9b73)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.3 to ^4.1.4 + * @libp2p/interface bumped from ^1.4.1 to ^1.5.0 + * @libp2p/interface-internal bumped from ^1.2.3 to ^1.2.4 + * @libp2p/logger bumped from ^4.0.14 to ^4.0.15 + * @libp2p/multistream-select bumped from ^5.1.11 to ^5.1.12 + * @libp2p/peer-collections bumped from ^5.2.3 to ^5.2.4 + * @libp2p/peer-id bumped from ^4.1.3 to ^4.1.4 + * @libp2p/peer-id-factory bumped from ^4.1.3 to ^4.1.4 + * @libp2p/peer-store bumped from ^10.0.20 to ^10.1.0 + * @libp2p/utils bumped from ^5.4.3 to ^5.4.4 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.25 to ^1.1.0 + * @libp2p/identify bumped from ^2.0.3 to ^2.1.0 + * @libp2p/interface-compliance-tests bumped from ^5.4.6 to ^5.4.7 + * @libp2p/mplex bumped from ^10.0.25 to ^10.1.0 + * @libp2p/plaintext bumped from ^1.0.25 to ^1.1.0 + * @libp2p/tcp bumped from ^9.0.27 to ^9.1.0 + * @libp2p/websockets bumped from ^8.0.25 to ^8.1.0 + +## [1.6.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.6.0...libp2p-v1.6.1) (2024-06-07) + + +### Bug Fixes + +* use randomwalk to find circuit relay servers ([#2563](https://github.com/libp2p/js-libp2p/issues/2563)) ([440c9b3](https://github.com/libp2p/js-libp2p/commit/440c9b360b8413149f4a1404c3368f124b0f8a5e)), closes [#2545](https://github.com/libp2p/js-libp2p/issues/2545) + + +### Dependencies + +* bump aegir from 42.2.11 to 43.0.1 ([#2571](https://github.com/libp2p/js-libp2p/issues/2571)) ([757fb26](https://github.com/libp2p/js-libp2p/commit/757fb2674f0a3e06fd46d3ff63f7f461c32d47d2)) +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.2 to ^4.1.3 + * @libp2p/interface bumped from ^1.4.0 to ^1.4.1 + * @libp2p/interface-internal bumped from ^1.2.2 to ^1.2.3 + * @libp2p/logger bumped from ^4.0.13 to ^4.0.14 + * @libp2p/multistream-select bumped from ^5.1.10 to ^5.1.11 + * @libp2p/peer-collections bumped from ^5.2.2 to ^5.2.3 + * @libp2p/peer-id bumped from ^4.1.2 to ^4.1.3 + * @libp2p/peer-id-factory bumped from ^4.1.2 to ^4.1.3 + * @libp2p/peer-store bumped from ^10.0.19 to ^10.0.20 + * @libp2p/utils bumped from ^5.4.2 to ^5.4.3 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.24 to ^1.0.25 + * @libp2p/identify bumped from ^2.0.2 to ^2.0.3 + * @libp2p/interface-compliance-tests bumped from ^5.4.5 to ^5.4.6 + * @libp2p/mplex bumped from ^10.0.24 to ^10.0.25 + * @libp2p/plaintext bumped from ^1.0.24 to ^1.0.25 + * @libp2p/tcp bumped from ^9.0.26 to ^9.0.27 + * @libp2p/websockets bumped from ^8.0.24 to ^8.0.25 + +## [1.6.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.5.2...libp2p-v1.6.0) (2024-05-17) + + +### Features + +* add optional topology filter ([#2544](https://github.com/libp2p/js-libp2p/issues/2544)) ([3c73707](https://github.com/libp2p/js-libp2p/commit/3c73707ff5c1635d4ab26dcc39499ab497d217a6)) + + +### Bug Fixes + +* log error correctly ([#2552](https://github.com/libp2p/js-libp2p/issues/2552)) ([a3e8bea](https://github.com/libp2p/js-libp2p/commit/a3e8beabdc2b551594952b5d5621555296eff79a)) +* update project config ([48444f7](https://github.com/libp2p/js-libp2p/commit/48444f750ebe3f03290bf70e84d7590edc030ea4)) + + +### Dependencies + +* bump sinon from 17.0.2 to 18.0.0 ([#2548](https://github.com/libp2p/js-libp2p/issues/2548)) ([1eb5b27](https://github.com/libp2p/js-libp2p/commit/1eb5b2713585e0d4dde927ecd307ada0b774d824)) +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.1 to ^4.1.2 + * @libp2p/interface bumped from ^1.3.1 to ^1.4.0 + * @libp2p/interface-internal bumped from ^1.2.1 to ^1.2.2 + * @libp2p/logger bumped from ^4.0.12 to ^4.0.13 + * @libp2p/multistream-select bumped from ^5.1.9 to ^5.1.10 + * @libp2p/peer-collections bumped from ^5.2.1 to ^5.2.2 + * @libp2p/peer-id bumped from ^4.1.1 to ^4.1.2 + * @libp2p/peer-id-factory bumped from ^4.1.1 to ^4.1.2 + * @libp2p/peer-store bumped from ^10.0.18 to ^10.0.19 + * @libp2p/utils bumped from ^5.4.1 to ^5.4.2 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.23 to ^1.0.24 + * @libp2p/identify bumped from ^2.0.1 to ^2.0.2 + * @libp2p/interface-compliance-tests bumped from ^5.4.4 to ^5.4.5 + * @libp2p/mplex bumped from ^10.0.23 to ^10.0.24 + * @libp2p/plaintext bumped from ^1.0.23 to ^1.0.24 + * @libp2p/tcp bumped from ^9.0.25 to ^9.0.26 + * @libp2p/websockets bumped from ^8.0.23 to ^8.0.24 + +## [1.5.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.5.1...libp2p-v1.5.2) (2024-05-14) + + +### Bug Fixes + +* add randomwalk to components ([#2518](https://github.com/libp2p/js-libp2p/issues/2518)) ([a11e135](https://github.com/libp2p/js-libp2p/commit/a11e135c221543b20fe746ab8ae85d54316ffe97)) +* pass autodial config thorugh in connection manager init ([#2523](https://github.com/libp2p/js-libp2p/issues/2523)) ([767b23e](https://github.com/libp2p/js-libp2p/commit/767b23e710b1a9b545421365f2f9603c37cbec78)) +* prune connections based on stream counts and direction ([#2521](https://github.com/libp2p/js-libp2p/issues/2521)) ([8e36fc5](https://github.com/libp2p/js-libp2p/commit/8e36fc5094c69083989650ccf3dfff001e5b0034)) +* use xor-compare for finding closer peers ([#2538](https://github.com/libp2p/js-libp2p/issues/2538)) ([83c14d0](https://github.com/libp2p/js-libp2p/commit/83c14d08f4f10a207f142f0d7d383e0fbff7858a)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^1.2.0 to ^1.2.1 + * @libp2p/peer-collections bumped from ^5.2.0 to ^5.2.1 + * @libp2p/peer-store bumped from ^10.0.17 to ^10.0.18 + * @libp2p/utils bumped from ^5.4.0 to ^5.4.1 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.22 to ^1.0.23 + * @libp2p/identify bumped from ^2.0.0 to ^2.0.1 + * @libp2p/interface-compliance-tests bumped from ^5.4.3 to ^5.4.4 + * @libp2p/mplex bumped from ^10.0.22 to ^10.0.23 + * @libp2p/plaintext bumped from ^1.0.22 to ^1.0.23 + * @libp2p/tcp bumped from ^9.0.24 to ^9.0.25 + * @libp2p/websockets bumped from ^8.0.22 to ^8.0.23 + +## [1.5.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.5.0...libp2p-v1.5.1) (2024-05-01) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/identify bumped from ^1.0.21 to ^2.0.0 + +## [1.5.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.4.3...libp2p-v1.5.0) (2024-05-01) + + +### Features + +* add random walk component ([#2501](https://github.com/libp2p/js-libp2p/issues/2501)) ([998fcaf](https://github.com/libp2p/js-libp2p/commit/998fcaf94889251817a3bbaaad9b654bebdf3a6e)) + + +### Bug Fixes + +* support validating asymmetric addresses ([#2515](https://github.com/libp2p/js-libp2p/issues/2515)) ([c824323](https://github.com/libp2p/js-libp2p/commit/c824323128bda325fc7af5a42cd0f1287c945bc4)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.1.0 to ^4.1.1 + * @libp2p/interface bumped from ^1.3.0 to ^1.3.1 + * @libp2p/interface-internal bumped from ^1.1.1 to ^1.2.0 + * @libp2p/logger bumped from ^4.0.11 to ^4.0.12 + * @libp2p/multistream-select bumped from ^5.1.8 to ^5.1.9 + * @libp2p/peer-collections bumped from ^5.1.11 to ^5.2.0 + * @libp2p/peer-id bumped from ^4.1.0 to ^4.1.1 + * @libp2p/peer-id-factory bumped from ^4.1.0 to ^4.1.1 + * @libp2p/peer-store bumped from ^10.0.16 to ^10.0.17 + * @libp2p/utils bumped from ^5.3.2 to ^5.4.0 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.21 to ^1.0.22 + * @libp2p/identify bumped from ^1.0.20 to ^1.0.21 + * @libp2p/interface-compliance-tests bumped from ^5.4.2 to ^5.4.3 + * @libp2p/mplex bumped from ^10.0.21 to ^10.0.22 + * @libp2p/plaintext bumped from ^1.0.21 to ^1.0.22 + * @libp2p/tcp bumped from ^9.0.23 to ^9.0.24 + * @libp2p/websockets bumped from ^8.0.21 to ^8.0.22 + +## [1.4.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.4.2...libp2p-v1.4.3) (2024-04-24) + + +### Bug Fixes + +* upgrader error msg to show current/max ([#2491](https://github.com/libp2p/js-libp2p/issues/2491)) ([eaf8ac7](https://github.com/libp2p/js-libp2p/commit/eaf8ac7cfb8a8ee00283de304dc4ec5280a41f1b)) + + +### Documentation + +* fix broken links in docs site ([#2497](https://github.com/libp2p/js-libp2p/issues/2497)) ([fd1f834](https://github.com/libp2p/js-libp2p/commit/fd1f8343db030d74cd08bca6a0cffda93532765f)), closes [#2423](https://github.com/libp2p/js-libp2p/issues/2423) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.0.6 to ^4.1.0 + * @libp2p/interface bumped from ^1.2.0 to ^1.3.0 + * @libp2p/interface-internal bumped from ^1.1.0 to ^1.1.1 + * @libp2p/logger bumped from ^4.0.10 to ^4.0.11 + * @libp2p/multistream-select bumped from ^5.1.7 to ^5.1.8 + * @libp2p/peer-collections bumped from ^5.1.10 to ^5.1.11 + * @libp2p/peer-id bumped from ^4.0.10 to ^4.1.0 + * @libp2p/peer-id-factory bumped from ^4.0.10 to ^4.1.0 + * @libp2p/peer-store bumped from ^10.0.15 to ^10.0.16 + * @libp2p/utils bumped from ^5.3.1 to ^5.3.2 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.20 to ^1.0.21 + * @libp2p/identify bumped from ^1.0.19 to ^1.0.20 + * @libp2p/interface-compliance-tests bumped from ^5.4.1 to ^5.4.2 + * @libp2p/mplex bumped from ^10.0.20 to ^10.0.21 + * @libp2p/plaintext bumped from ^1.0.20 to ^1.0.21 + * @libp2p/tcp bumped from ^9.0.22 to ^9.0.23 + * @libp2p/websockets bumped from ^8.0.20 to ^8.0.21 + +## [1.4.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.4.1...libp2p-v1.4.2) (2024-04-16) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/tcp bumped from ^9.0.21 to ^9.0.22 + +## [1.4.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.4.0...libp2p-v1.4.1) (2024-04-15) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/peer-store bumped from ^10.0.14 to ^10.0.15 + * @libp2p/utils bumped from ^5.3.0 to ^5.3.1 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.19 to ^1.0.20 + * @libp2p/identify bumped from ^1.0.18 to ^1.0.19 + * @libp2p/interface-compliance-tests bumped from ^5.4.0 to ^5.4.1 + * @libp2p/mplex bumped from ^10.0.19 to ^10.0.20 + * @libp2p/plaintext bumped from ^1.0.19 to ^1.0.20 + * @libp2p/tcp bumped from ^9.0.20 to ^9.0.21 + * @libp2p/websockets bumped from ^8.0.19 to ^8.0.20 + +## [1.4.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.3.3...libp2p-v1.4.0) (2024-04-12) + + +### Features + +* add isDialable method to libp2p ([#2479](https://github.com/libp2p/js-libp2p/issues/2479)) ([2c56203](https://github.com/libp2p/js-libp2p/commit/2c56203f9ccf4b6ed30541a871b9bd8c5a21526e)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.0.5 to ^4.0.6 + * @libp2p/interface bumped from ^1.1.6 to ^1.2.0 + * @libp2p/interface-internal bumped from ^1.0.11 to ^1.1.0 + * @libp2p/logger bumped from ^4.0.9 to ^4.0.10 + * @libp2p/multistream-select bumped from ^5.1.6 to ^5.1.7 + * @libp2p/peer-collections bumped from ^5.1.9 to ^5.1.10 + * @libp2p/peer-id bumped from ^4.0.9 to ^4.0.10 + * @libp2p/peer-id-factory bumped from ^4.0.9 to ^4.0.10 + * @libp2p/peer-store bumped from ^10.0.13 to ^10.0.14 + * @libp2p/utils bumped from ^5.2.8 to ^5.3.0 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.18 to ^1.0.19 + * @libp2p/identify bumped from ^1.0.17 to ^1.0.18 + * @libp2p/interface-compliance-tests bumped from ^5.3.4 to ^5.4.0 + * @libp2p/mplex bumped from ^10.0.18 to ^10.0.19 + * @libp2p/plaintext bumped from ^1.0.18 to ^1.0.19 + * @libp2p/tcp bumped from ^9.0.19 to ^9.0.20 + * @libp2p/websockets bumped from ^8.0.18 to ^8.0.19 + +## [1.3.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.3.2...libp2p-v1.3.3) (2024-04-09) + + +### Bug Fixes + +* decrease default dial timeout ([#2471](https://github.com/libp2p/js-libp2p/issues/2471)) ([936dbba](https://github.com/libp2p/js-libp2p/commit/936dbba108093503cb68ea248dd03c3f8ccde8e7)) +* limit max dial queue size ([#2472](https://github.com/libp2p/js-libp2p/issues/2472)) ([0cfcc4d](https://github.com/libp2p/js-libp2p/commit/0cfcc4da195f6eb5b98f5b549cd92607fc3b8aa9)) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/tcp bumped from ^9.0.18 to ^9.0.19 + +## [1.3.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.3.1...libp2p-v1.3.2) (2024-04-05) + + +### Bug Fixes + +* add @libp2p/record module to monorepo ([#2466](https://github.com/libp2p/js-libp2p/issues/2466)) ([3ffecc5](https://github.com/libp2p/js-libp2p/commit/3ffecc5bfe806a678c1b0228ff830f1811630718)) + + +### Documentation + +* update typos in Address Manager and comments ([#2468](https://github.com/libp2p/js-libp2p/issues/2468)) ([a2b41f7](https://github.com/libp2p/js-libp2p/commit/a2b41f7939806dfb9583a6d43ddd8764fc861baf)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.0.4 to ^4.0.5 + * @libp2p/interface bumped from ^1.1.5 to ^1.1.6 + * @libp2p/interface-internal bumped from ^1.0.10 to ^1.0.11 + * @libp2p/logger bumped from ^4.0.8 to ^4.0.9 + * @libp2p/multistream-select bumped from ^5.1.5 to ^5.1.6 + * @libp2p/peer-collections bumped from ^5.1.8 to ^5.1.9 + * @libp2p/peer-id bumped from ^4.0.8 to ^4.0.9 + * @libp2p/peer-id-factory bumped from ^4.0.8 to ^4.0.9 + * @libp2p/peer-store bumped from ^10.0.12 to ^10.0.13 + * @libp2p/utils bumped from ^5.2.7 to ^5.2.8 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.17 to ^1.0.18 + * @libp2p/identify bumped from ^1.0.16 to ^1.0.17 + * @libp2p/interface-compliance-tests bumped from ^5.3.3 to ^5.3.4 + * @libp2p/mplex bumped from ^10.0.17 to ^10.0.18 + * @libp2p/plaintext bumped from ^1.0.17 to ^1.0.18 + * @libp2p/tcp bumped from ^9.0.17 to ^9.0.18 + * @libp2p/websockets bumped from ^8.0.17 to ^8.0.18 + +## [1.3.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.3.0...libp2p-v1.3.1) (2024-03-28) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.0.3 to ^4.0.4 + * @libp2p/interface bumped from ^1.1.4 to ^1.1.5 + * @libp2p/interface-internal bumped from ^1.0.9 to ^1.0.10 + * @libp2p/logger bumped from ^4.0.7 to ^4.0.8 + * @libp2p/multistream-select bumped from ^5.1.4 to ^5.1.5 + * @libp2p/peer-collections bumped from ^5.1.7 to ^5.1.8 + * @libp2p/peer-id bumped from ^4.0.7 to ^4.0.8 + * @libp2p/peer-id-factory bumped from ^4.0.7 to ^4.0.8 + * @libp2p/peer-store bumped from ^10.0.11 to ^10.0.12 + * @libp2p/utils bumped from ^5.2.6 to ^5.2.7 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.16 to ^1.0.17 + * @libp2p/identify bumped from ^1.0.15 to ^1.0.16 + * @libp2p/interface-compliance-tests bumped from ^5.3.2 to ^5.3.3 + * @libp2p/mplex bumped from ^10.0.16 to ^10.0.17 + * @libp2p/plaintext bumped from ^1.0.16 to ^1.0.17 + * @libp2p/tcp bumped from ^9.0.16 to ^9.0.17 + * @libp2p/websockets bumped from ^8.0.16 to ^8.0.17 + +## [1.3.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.2.4...libp2p-v1.3.0) (2024-03-12) + + +### Features + +* support custom DNS resolvers ([#2435](https://github.com/libp2p/js-libp2p/issues/2435)) ([f39ce5f](https://github.com/libp2p/js-libp2p/commit/f39ce5f13b56e2a18c7939b9d2ab38aa7e326d15)) + +## [1.2.4](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.2.3...libp2p-v1.2.4) (2024-02-27) + + +### Bug Fixes + +* silence max listeners warning ([#2417](https://github.com/libp2p/js-libp2p/issues/2417)) ([bedfd0a](https://github.com/libp2p/js-libp2p/commit/bedfd0aa20a83e0823744c298007ef58a76a26ae)) + + +### Documentation + +* add doc-check to all modules ([#2419](https://github.com/libp2p/js-libp2p/issues/2419)) ([6cdb243](https://github.com/libp2p/js-libp2p/commit/6cdb24362de9991e749f76b16fcd4c130e8106a0)) +* add Peerbit logo ([#2402](https://github.com/libp2p/js-libp2p/issues/2402)) ([fb7c51c](https://github.com/libp2p/js-libp2p/commit/fb7c51c3c03c462ac4d2b42b32be95cd008c81fc)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.0.2 to ^4.0.3 + * @libp2p/interface bumped from ^1.1.3 to ^1.1.4 + * @libp2p/interface-internal bumped from ^1.0.8 to ^1.0.9 + * @libp2p/logger bumped from ^4.0.6 to ^4.0.7 + * @libp2p/multistream-select bumped from ^5.1.3 to ^5.1.4 + * @libp2p/peer-collections bumped from ^5.1.6 to ^5.1.7 + * @libp2p/peer-id bumped from ^4.0.6 to ^4.0.7 + * @libp2p/peer-id-factory bumped from ^4.0.6 to ^4.0.7 + * @libp2p/peer-store bumped from ^10.0.10 to ^10.0.11 + * @libp2p/utils bumped from ^5.2.5 to ^5.2.6 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.15 to ^1.0.16 + * @libp2p/identify bumped from ^1.0.14 to ^1.0.15 + * @libp2p/interface-compliance-tests bumped from ^5.3.1 to ^5.3.2 + * @libp2p/mplex bumped from ^10.0.15 to ^10.0.16 + * @libp2p/plaintext bumped from ^1.0.15 to ^1.0.16 + * @libp2p/tcp bumped from ^9.0.15 to ^9.0.16 + * @libp2p/websockets bumped from ^8.0.15 to ^8.0.16 + +## [1.2.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.2.1...libp2p-v1.2.2) (2024-02-07) + + +### Bug Fixes + +* update patch versions of deps ([#2397](https://github.com/libp2p/js-libp2p/issues/2397)) ([0321812](https://github.com/libp2p/js-libp2p/commit/0321812e731515558f35ae2d53242035a343a21a)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.0.1 to ^4.0.2 + * @libp2p/interface bumped from ^1.1.2 to ^1.1.3 + * @libp2p/interface-internal bumped from ^1.0.7 to ^1.0.8 + * @libp2p/logger bumped from ^4.0.5 to ^4.0.6 + * @libp2p/multistream-select bumped from ^5.1.2 to ^5.1.3 + * @libp2p/peer-collections bumped from ^5.1.5 to ^5.1.6 + * @libp2p/peer-id bumped from ^4.0.5 to ^4.0.6 + * @libp2p/peer-id-factory bumped from ^4.0.5 to ^4.0.6 + * @libp2p/peer-store bumped from ^10.0.8 to ^10.0.9 + * @libp2p/utils bumped from ^5.2.3 to ^5.2.4 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.13 to ^1.0.14 + * @libp2p/identify bumped from ^1.0.12 to ^1.0.13 + * @libp2p/interface-compliance-tests bumped from ^5.2.0 to ^5.3.0 + * @libp2p/mplex bumped from ^10.0.13 to ^10.0.14 + * @libp2p/plaintext bumped from ^1.0.13 to ^1.0.14 + * @libp2p/tcp bumped from ^9.0.13 to ^9.0.14 + * @libp2p/websockets bumped from ^8.0.13 to ^8.0.14 + +## [1.2.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.2.0...libp2p-v1.2.1) (2024-01-24) + + +### Bug Fixes + +* add local definition of isPrivateIp ([#2362](https://github.com/libp2p/js-libp2p/issues/2362)) ([f27138c](https://github.com/libp2p/js-libp2p/commit/f27138ca1f552c4ad3e5d325fef626ba6783f0fd)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/peer-store bumped from ^10.0.7 to ^10.0.8 + * @libp2p/utils bumped from ^5.2.2 to ^5.2.3 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.12 to ^1.0.13 + * @libp2p/identify bumped from ^1.0.11 to ^1.0.12 + * @libp2p/interface-compliance-tests bumped from ^5.1.3 to ^5.2.0 + * @libp2p/mplex bumped from ^10.0.12 to ^10.0.13 + * @libp2p/plaintext bumped from ^1.0.12 to ^1.0.13 + * @libp2p/tcp bumped from ^9.0.12 to ^9.0.13 + * @libp2p/websockets bumped from ^8.0.12 to ^8.0.13 + +## [1.2.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.1.2...libp2p-v1.2.0) (2024-01-16) + + +### Features + +* add private key to libp2p components ([#2348](https://github.com/libp2p/js-libp2p/issues/2348)) ([092861e](https://github.com/libp2p/js-libp2p/commit/092861e23271921b3cef2e673f6f0c9b0c3ab325)) + + +### Bug Fixes + +* align dependency versions and update project config ([#2357](https://github.com/libp2p/js-libp2p/issues/2357)) ([8bbd436](https://github.com/libp2p/js-libp2p/commit/8bbd43628343f995804eea3102d0571ddcebc5c4)) +* mark all packages side-effect free ([#2360](https://github.com/libp2p/js-libp2p/issues/2360)) ([3c96210](https://github.com/libp2p/js-libp2p/commit/3c96210cf6343b21199996918bae3a0f60220046)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^4.0.0 to ^4.0.1 + * @libp2p/interface bumped from ^1.1.1 to ^1.1.2 + * @libp2p/interface-internal bumped from ^1.0.6 to ^1.0.7 + * @libp2p/logger bumped from ^4.0.4 to ^4.0.5 + * @libp2p/multistream-select bumped from ^5.1.1 to ^5.1.2 + * @libp2p/peer-collections bumped from ^5.1.4 to ^5.1.5 + * @libp2p/peer-id bumped from ^4.0.4 to ^4.0.5 + * @libp2p/peer-id-factory bumped from ^4.0.4 to ^4.0.5 + * @libp2p/peer-store bumped from ^10.0.6 to ^10.0.7 + * @libp2p/utils bumped from ^5.2.1 to ^5.2.2 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.11 to ^1.0.12 + * @libp2p/identify bumped from ^1.0.10 to ^1.0.11 + * @libp2p/interface-compliance-tests bumped from ^5.1.2 to ^5.1.3 + * @libp2p/mplex bumped from ^10.0.11 to ^10.0.12 + * @libp2p/plaintext bumped from ^1.0.11 to ^1.0.12 + * @libp2p/tcp bumped from ^9.0.11 to ^9.0.12 + * @libp2p/websockets bumped from ^8.0.11 to ^8.0.12 + +## [1.1.2](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.1.1...libp2p-v1.1.2) (2024-01-12) + + +### Bug Fixes + +* query routing for RSA public key ([#2350](https://github.com/libp2p/js-libp2p/issues/2350)) ([ee7ffe9](https://github.com/libp2p/js-libp2p/commit/ee7ffe9b9209d1ef0ffbd71389216b69e832b126)) +* replace rate-limiter ([#2356](https://github.com/libp2p/js-libp2p/issues/2356)) ([ddaa59a](https://github.com/libp2p/js-libp2p/commit/ddaa59a600c031fe1f41ba2097ebfcfd74eff598)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^3.0.4 to ^4.0.0 + * @libp2p/interface-internal bumped from ^1.0.5 to ^1.0.6 + * @libp2p/peer-collections bumped from ^5.1.3 to ^5.1.4 + * @libp2p/peer-id-factory bumped from ^4.0.3 to ^4.0.4 + * @libp2p/peer-store bumped from ^10.0.5 to ^10.0.6 + * @libp2p/utils bumped from ^5.2.0 to ^5.2.1 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.10 to ^1.0.11 + * @libp2p/identify bumped from ^1.0.9 to ^1.0.10 + * @libp2p/interface-compliance-tests bumped from ^5.1.1 to ^5.1.2 + * @libp2p/mplex bumped from ^10.0.10 to ^10.0.11 + * @libp2p/plaintext bumped from ^1.0.10 to ^1.0.11 + * @libp2p/tcp bumped from ^9.0.10 to ^9.0.11 + * @libp2p/websockets bumped from ^8.0.10 to ^8.0.11 + +## [1.1.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.1.0...libp2p-v1.1.1) (2024-01-06) + + +### Bug Fixes + +* perform find peer during dial if peer has no multiaddrs ([#2345](https://github.com/libp2p/js-libp2p/issues/2345)) ([444d837](https://github.com/libp2p/js-libp2p/commit/444d83751fa5137c76d0a265544bb3522da24a3c)) +* remove extra deps ([#2340](https://github.com/libp2p/js-libp2p/issues/2340)) ([53e83ee](https://github.com/libp2p/js-libp2p/commit/53e83eea50410391ec9cff4cd8097210b93894ff)) +* replace p-queue with less restrictive queue ([#2339](https://github.com/libp2p/js-libp2p/issues/2339)) ([528d737](https://github.com/libp2p/js-libp2p/commit/528d73781f416ea97af044bb49d9701f97c9eeec)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^3.0.3 to ^3.0.4 + * @libp2p/interface bumped from ^1.1.0 to ^1.1.1 + * @libp2p/interface-internal bumped from ^1.0.4 to ^1.0.5 + * @libp2p/logger bumped from ^4.0.3 to ^4.0.4 + * @libp2p/multistream-select bumped from ^5.1.0 to ^5.1.1 + * @libp2p/peer-collections bumped from ^5.1.2 to ^5.1.3 + * @libp2p/peer-id bumped from ^4.0.3 to ^4.0.4 + * @libp2p/peer-id-factory bumped from ^4.0.2 to ^4.0.3 + * @libp2p/peer-store bumped from ^10.0.4 to ^10.0.5 + * @libp2p/utils bumped from ^5.1.1 to ^5.2.0 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.9 to ^1.0.10 + * @libp2p/identify bumped from ^1.0.8 to ^1.0.9 + * @libp2p/interface-compliance-tests bumped from ^5.1.0 to ^5.1.1 + * @libp2p/mplex bumped from ^10.0.9 to ^10.0.10 + * @libp2p/plaintext bumped from ^1.0.9 to ^1.0.10 + * @libp2p/tcp bumped from ^9.0.9 to ^9.0.10 + * @libp2p/websockets bumped from ^8.0.9 to ^8.0.10 + +## [1.1.0](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.12...libp2p-v1.1.0) (2023-12-28) + + +### Features + +* add `negotiateFully` option when opening streams ([#2331](https://github.com/libp2p/js-libp2p/issues/2331)) ([5d1f68e](https://github.com/libp2p/js-libp2p/commit/5d1f68e9257820c34aec07cf5c94b8f71ed8a69e)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^3.0.2 to ^3.0.3 + * @libp2p/interface bumped from ^1.0.2 to ^1.1.0 + * @libp2p/interface-internal bumped from ^1.0.3 to ^1.0.4 + * @libp2p/logger bumped from ^4.0.2 to ^4.0.3 + * @libp2p/multistream-select bumped from ^5.0.3 to ^5.1.0 + * @libp2p/peer-collections bumped from ^5.1.1 to ^5.1.2 + * @libp2p/peer-id bumped from ^4.0.2 to ^4.0.3 + * @libp2p/peer-id-factory bumped from ^4.0.1 to ^4.0.2 + * @libp2p/peer-store bumped from ^10.0.3 to ^10.0.4 + * @libp2p/utils bumped from ^5.1.0 to ^5.1.1 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.8 to ^1.0.9 + * @libp2p/identify bumped from ^1.0.7 to ^1.0.8 + * @libp2p/interface-compliance-tests bumped from ^5.0.8 to ^5.1.0 + * @libp2p/mplex bumped from ^10.0.8 to ^10.0.9 + * @libp2p/plaintext bumped from ^1.0.8 to ^1.0.9 + * @libp2p/tcp bumped from ^9.0.8 to ^9.0.9 + * @libp2p/websockets bumped from ^8.0.8 to ^8.0.9 + +## [1.0.12](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.11...libp2p-v1.0.12) (2023-12-20) + + +### Bug Fixes + +* reset dial queue shut down controller on node restart ([#2329](https://github.com/libp2p/js-libp2p/issues/2329)) ([cd8cafc](https://github.com/libp2p/js-libp2p/commit/cd8cafcd5c6aa141aba855a4de4c12336c429913)), closes [#2188](https://github.com/libp2p/js-libp2p/issues/2188) + +## [1.0.11](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.10...libp2p-v1.0.11) (2023-12-19) + + +### Bug Fixes + +* update log messages ([#2324](https://github.com/libp2p/js-libp2p/issues/2324)) ([984f13e](https://github.com/libp2p/js-libp2p/commit/984f13e4223e724a358d8cc9134cbba435b08512)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/multistream-select bumped from ^5.0.2 to ^5.0.3 + * @libp2p/peer-store bumped from ^10.0.2 to ^10.0.3 + * @libp2p/utils bumped from ^5.0.3 to ^5.1.0 + * devDependencies + * @libp2p/circuit-relay-v2 bumped from ^1.0.7 to ^1.0.8 + * @libp2p/identify bumped from ^1.0.6 to ^1.0.7 + * @libp2p/interface-compliance-tests bumped from ^5.0.7 to ^5.0.8 + * @libp2p/mplex bumped from ^10.0.7 to ^10.0.8 + * @libp2p/plaintext bumped from ^1.0.7 to ^1.0.8 + * @libp2p/tcp bumped from ^9.0.7 to ^9.0.8 + * @libp2p/websockets bumped from ^8.0.7 to ^8.0.8 + +## [1.0.10](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.9...libp2p-v1.0.10) (2023-12-10) + + +### Bug Fixes + +* react native adjustments ([#2229](https://github.com/libp2p/js-libp2p/issues/2229)) ([3415811](https://github.com/libp2p/js-libp2p/commit/341581166fd5bd2ead6b9d9db1ffda84051b6262)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^3.0.1 to ^3.0.2 + * @libp2p/interface bumped from ^1.0.1 to ^1.0.2 + * @libp2p/interface-internal bumped from ^1.0.2 to ^1.0.3 + * @libp2p/logger bumped from ^4.0.1 to ^4.0.2 + * @libp2p/multistream-select bumped from ^5.0.1 to ^5.0.2 + * @libp2p/peer-collections bumped from ^5.1.0 to ^5.1.1 + * @libp2p/peer-id bumped from ^4.0.1 to ^4.0.2 + * @libp2p/peer-id-factory bumped from ^4.0.0 to ^4.0.1 + * @libp2p/peer-store bumped from ^10.0.1 to ^10.0.2 + * @libp2p/utils bumped from ^5.0.2 to ^5.0.3 + * devDependencies + * @libp2p/bootstrap bumped from ^10.0.6 to ^10.0.7 + * @libp2p/circuit-relay-v2 bumped from ^1.0.6 to ^1.0.7 + * @libp2p/identify bumped from ^1.0.5 to ^1.0.6 + * @libp2p/interface-compliance-tests bumped from ^5.0.6 to ^5.0.7 + * @libp2p/kad-dht bumped from ^11.0.6 to ^11.0.7 + * @libp2p/mdns bumped from ^10.0.6 to ^10.0.7 + * @libp2p/mplex bumped from ^10.0.6 to ^10.0.7 + * @libp2p/plaintext bumped from ^1.0.6 to ^1.0.7 + * @libp2p/tcp bumped from ^9.0.6 to ^9.0.7 + * @libp2p/websockets bumped from ^8.0.6 to ^8.0.7 + +## [1.0.8](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.7...libp2p-v1.0.8) (2023-12-04) + + +### Bug Fixes + +* make transports optional ([#2295](https://github.com/libp2p/js-libp2p/issues/2295)) ([887c6ff](https://github.com/libp2p/js-libp2p/commit/887c6ffe1b38bc9f0219b861b36d71de59095a8e)) + +## [1.0.7](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.6...libp2p-v1.0.7) (2023-12-04) + + +### Bug Fixes + +* allow no transports in config ([#2293](https://github.com/libp2p/js-libp2p/issues/2293)) ([16588d2](https://github.com/libp2p/js-libp2p/commit/16588d27c8ca9c52686146160234534ee3dac915)) + +## [1.0.6](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.5...libp2p-v1.0.6) (2023-12-02) + + +### Bug Fixes + +* remove duplicate autodial from startup ([#2289](https://github.com/libp2p/js-libp2p/issues/2289)) ([bcfa159](https://github.com/libp2p/js-libp2p/commit/bcfa15993fd533c56c7523384e4b135c4930855b)) +* set libp2p status to started before stopping ([#2288](https://github.com/libp2p/js-libp2p/issues/2288)) ([09dd029](https://github.com/libp2p/js-libp2p/commit/09dd02987d84770547f7dfd347fa09a0a98d3081)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/multistream-select bumped from ^5.0.0 to ^5.0.1 + * devDependencies + * @libp2p/bootstrap bumped from ^10.0.4 to ^10.0.5 + * @libp2p/circuit-relay-v2 bumped from ^1.0.4 to ^1.0.5 + * @libp2p/identify bumped from ^1.0.3 to ^1.0.4 + * @libp2p/interface-compliance-tests bumped from ^5.0.4 to ^5.0.5 + * @libp2p/kad-dht bumped from ^11.0.4 to ^11.0.5 + * @libp2p/mdns bumped from ^10.0.4 to ^10.0.5 + * @libp2p/mplex bumped from ^10.0.4 to ^10.0.5 + * @libp2p/plaintext bumped from ^1.0.4 to ^1.0.5 + * @libp2p/tcp bumped from ^9.0.4 to ^9.0.5 + * @libp2p/websockets bumped from ^8.0.4 to ^8.0.5 + +## [1.0.3](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.2...libp2p-v1.0.3) (2023-12-01) + + +### Bug Fixes + +* export version from libp2p ([#2279](https://github.com/libp2p/js-libp2p/issues/2279)) ([8c169db](https://github.com/libp2p/js-libp2p/commit/8c169db1bcc923fa2edd3749e6669eb69d93f6b3)) +* log upgrade messages on connection ([#2281](https://github.com/libp2p/js-libp2p/issues/2281)) ([f537b37](https://github.com/libp2p/js-libp2p/commit/f537b37316c78d26939e9c8d04bcf67599992554)) + +## [1.0.1](https://github.com/libp2p/js-libp2p/compare/libp2p-v1.0.0...libp2p-v1.0.1) (2023-11-30) + + +### Bug Fixes + +* add status property ([#2269](https://github.com/libp2p/js-libp2p/issues/2269)) ([a32e70b](https://github.com/libp2p/js-libp2p/commit/a32e70bac126a0746dff9f7c87a4d6211a00fa7a)) +* restore lost commits ([#2268](https://github.com/libp2p/js-libp2p/issues/2268)) ([5775f1d](https://github.com/libp2p/js-libp2p/commit/5775f1df4f5561500e622dc0788fdacbc74e2755)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^3.0.0 to ^3.0.1 + * @libp2p/interface bumped from ^1.0.0 to ^1.0.1 + * @libp2p/interface-internal bumped from ^0.1.10 to ^0.1.11 + * @libp2p/logger bumped from ^4.0.0 to ^4.0.1 + * @libp2p/multistream-select bumped from ^4.0.7 to ^4.0.8 + * @libp2p/peer-collections bumped from ^4.0.9 to ^4.0.10 + * @libp2p/peer-id bumped from ^4.0.0 to ^4.0.1 + * @libp2p/peer-id-factory bumped from ^3.0.9 to ^3.0.10 + * @libp2p/peer-store bumped from ^9.0.10 to ^9.0.11 + * @libp2p/utils bumped from ^5.0.0 to ^5.0.1 + * devDependencies + * @libp2p/bootstrap bumped from ^10.0.0 to ^10.0.1 + * @libp2p/circuit-relay-v2 bumped from ^1.0.0 to ^1.0.1 + * @libp2p/floodsub bumped from ^8.0.14 to ^8.0.15 + * @libp2p/identify bumped from ^1.0.0 to ^1.0.1 + * @libp2p/interface-compliance-tests bumped from ^5.0.0 to ^5.0.1 + * @libp2p/kad-dht bumped from ^11.0.0 to ^11.0.1 + * @libp2p/mdns bumped from ^10.0.0 to ^10.0.1 + * @libp2p/mplex bumped from ^10.0.0 to ^10.0.1 + * @libp2p/plaintext bumped from ^1.0.0 to ^1.0.1 + * @libp2p/tcp bumped from ^9.0.0 to ^9.0.1 + * @libp2p/websockets bumped from ^8.0.0 to ^8.0.1 + +## [1.0.0](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.21...libp2p-v1.0.0) (2023-11-28) + + +### ⚠ BREAKING CHANGES + +* the `minSendBytes` option has been removed from Mplex since the transport can now decide how to optimise sending data +* remove per-peer parallel dialling (#2090) (#2251) +* imports from `libp2p/fetch` should be updated to `@libp2p/fetch` +* imports from `libp2p/circuit-relay` should be updated to `@libp2p/circuit-relay-v2` +* imports from `libp2p/plaintext` should be changed to `@libp2p/plaintext` +* imports from `libp2p/dcutr` now need to be from `@libp2p/dcutr` +* imports from `libp2p/identify` need to change to `@libp2p/identify` +* imports from `libp2p/ping` must be updated to `@libp2p/ping` +* imports from `libp2p/upnp-nat` should be updated to `@libp2p/upnp-nat` +* the `isStarted` method has been removed from the `Startable` interface +* the `.protocols` property has been removed from the `PeerInfo` interface +* move autonat into separate package (#2107) +* remove libp2p.keychain (#2084) +* remove dialler language (#2143) + +### Features + +* allow stream muxers and connection encrypters to yield lists ([#2256](https://www.github.com/libp2p/js-libp2p/issues/2256)) ([4a474d5](https://www.github.com/libp2p/js-libp2p/commit/4a474d54d3299e0ac30fa143b57436b3cf45e426)) + + +### Bug Fixes + +* allow mss lazy select on read ([#2246](https://www.github.com/libp2p/js-libp2p/issues/2246)) ([d8f5bc2](https://www.github.com/libp2p/js-libp2p/commit/d8f5bc211185a963c2a5182d58d73629457bc78d)) +* remove dialler language ([#2143](https://www.github.com/libp2p/js-libp2p/issues/2143)) ([a321f15](https://www.github.com/libp2p/js-libp2p/commit/a321f15329ba9b8e6a84a5a7429784edf7fa96e9)) +* remove protocols from PeerInfo ([#2166](https://www.github.com/libp2p/js-libp2p/issues/2166)) ([5468cd1](https://www.github.com/libp2p/js-libp2p/commit/5468cd13a76281e46b221fdbd7d4005c0d3f2252)) +* use logging component everywhere ([#2228](https://www.github.com/libp2p/js-libp2p/issues/2228)) ([e5dfde0](https://www.github.com/libp2p/js-libp2p/commit/e5dfde0883191c93903ca552433f177d48adf0b3)) +* use optimistic protocol negotation ([#2253](https://www.github.com/libp2p/js-libp2p/issues/2253)) ([0b4a2ee](https://www.github.com/libp2p/js-libp2p/commit/0b4a2ee7983b4dc9dc0a7b705a202a4c550e7017)) + + +### Code Refactoring + +* extract circuit relay v2 to separate module ([#2222](https://www.github.com/libp2p/js-libp2p/issues/2222)) ([24afba3](https://www.github.com/libp2p/js-libp2p/commit/24afba30004fb7f24af1f0180229bb164340f00b)) +* extract DCUtR into separate module ([#2220](https://www.github.com/libp2p/js-libp2p/issues/2220)) ([d2c3e72](https://www.github.com/libp2p/js-libp2p/commit/d2c3e7235b64558c6cace414c54a42659fee2970)) +* extract fetch to separate module ([#2223](https://www.github.com/libp2p/js-libp2p/issues/2223)) ([9b19be2](https://www.github.com/libp2p/js-libp2p/commit/9b19be2796c2dbbe207029199b1ac203647744e3)) +* extract identify service into separate module ([#2219](https://www.github.com/libp2p/js-libp2p/issues/2219)) ([72c2f77](https://www.github.com/libp2p/js-libp2p/commit/72c2f775bd85bd4928048dda0fd14740d6fb6a69)) +* extract ping service into separate module ([#2218](https://www.github.com/libp2p/js-libp2p/issues/2218)) ([556282a](https://www.github.com/libp2p/js-libp2p/commit/556282afdc9b328fd58df1045dc7c792199be932)) +* extract plaintext into separate module ([#2221](https://www.github.com/libp2p/js-libp2p/issues/2221)) ([a364d95](https://www.github.com/libp2p/js-libp2p/commit/a364d95bbd7b15a5ce6ce508321e7ff2fa40a5e5)) +* extract UPnP NAT into separate module ([#2217](https://www.github.com/libp2p/js-libp2p/issues/2217)) ([f29b73f](https://www.github.com/libp2p/js-libp2p/commit/f29b73f781afcea36cba0589aafdd81e1852e194)) +* move autonat into separate package ([#2107](https://www.github.com/libp2p/js-libp2p/issues/2107)) ([b0e8f06](https://www.github.com/libp2p/js-libp2p/commit/b0e8f06f0dcdbda0e367186b093e42e8bff3ee27)) +* remove isStarted method from Startable ([#2145](https://www.github.com/libp2p/js-libp2p/issues/2145)) ([fca208f](https://www.github.com/libp2p/js-libp2p/commit/fca208f3763af041aa37b1cb915d2bc777acb96d)) +* remove libp2p.keychain ([#2084](https://www.github.com/libp2p/js-libp2p/issues/2084)) ([125c84b](https://www.github.com/libp2p/js-libp2p/commit/125c84bb8a30ac986fb5aed0a4de23bc806d3aea)) +* remove per-peer parallel dialling ([#2090](https://www.github.com/libp2p/js-libp2p/issues/2090)) ([#2251](https://www.github.com/libp2p/js-libp2p/issues/2251)) ([bb6ceb1](https://www.github.com/libp2p/js-libp2p/commit/bb6ceb19252de2c1441ef736127d13763837d644)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.8 to ^3.0.0 + * @libp2p/interface bumped from ^0.1.6 to ^1.0.0 + * @libp2p/interface-internal bumped from ^0.1.9 to ^0.1.10 + * @libp2p/logger bumped from ^3.1.0 to ^4.0.0 + * @libp2p/multistream-select bumped from ^4.0.6 to ^4.0.7 + * @libp2p/peer-collections bumped from ^4.0.8 to ^4.0.9 + * @libp2p/peer-id bumped from ^3.0.6 to ^4.0.0 + * @libp2p/peer-id-factory bumped from ^3.0.8 to ^3.0.9 + * @libp2p/peer-store bumped from ^9.0.9 to ^9.0.10 + * @libp2p/utils bumped from ^4.0.7 to ^5.0.0 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.12 to ^10.0.0 + * @libp2p/circuit-relay-v2 bumped from ^0.0.0 to ^1.0.0 + * @libp2p/floodsub bumped from ^8.0.13 to ^8.0.14 + * @libp2p/identify bumped from ^0.0.0 to ^1.0.0 + * @libp2p/interface-compliance-tests bumped from ^4.1.5 to ^5.0.0 + * @libp2p/kad-dht bumped from ^10.0.15 to ^11.0.0 + * @libp2p/mdns bumped from ^9.0.14 to ^10.0.0 + * @libp2p/mplex bumped from ^9.0.12 to ^10.0.0 + * @libp2p/plaintext bumped from ^0.0.0 to ^1.0.0 + * @libp2p/tcp bumped from ^8.0.13 to ^9.0.0 + * @libp2p/websockets bumped from ^7.0.13 to ^8.0.0 + +### [0.46.21](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.20...libp2p-v0.46.21) (2023-11-10) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/kad-dht bumped from ^10.0.14 to ^10.0.15 + +### [0.46.20](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.19...libp2p-v0.46.20) (2023-11-07) + + +### Features + +* add component logger ([#2198](https://www.github.com/libp2p/js-libp2p/issues/2198)) ([fb8a6f1](https://www.github.com/libp2p/js-libp2p/commit/fb8a6f1887e71852217355f65c2b22566dd26749)), closes [#2105](https://www.github.com/libp2p/js-libp2p/issues/2105) + + +### Bug Fixes + +* do not overwrite signal property of options ([#2214](https://www.github.com/libp2p/js-libp2p/issues/2214)) ([70d5efc](https://www.github.com/libp2p/js-libp2p/commit/70d5efc2e901a2c419fe3f82d767f278b6d698fd)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.7 to ^2.0.8 + * @libp2p/interface bumped from ^0.1.5 to ^0.1.6 + * @libp2p/interface-internal bumped from ^0.1.8 to ^0.1.9 + * @libp2p/keychain bumped from ^3.0.7 to ^3.0.8 + * @libp2p/logger bumped from ^3.0.5 to ^3.1.0 + * @libp2p/multistream-select bumped from ^4.0.5 to ^4.0.6 + * @libp2p/peer-collections bumped from ^4.0.7 to ^4.0.8 + * @libp2p/peer-id bumped from ^3.0.5 to ^3.0.6 + * @libp2p/peer-id-factory bumped from ^3.0.7 to ^3.0.8 + * @libp2p/peer-record bumped from ^6.0.8 to ^6.0.9 + * @libp2p/peer-store bumped from ^9.0.8 to ^9.0.9 + * @libp2p/utils bumped from ^4.0.6 to ^4.0.7 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.11 to ^9.0.12 + * @libp2p/floodsub bumped from ^8.0.12 to ^8.0.13 + * @libp2p/interface-compliance-tests bumped from ^4.1.4 to ^4.1.5 + * @libp2p/kad-dht bumped from ^10.0.13 to ^10.0.14 + * @libp2p/mdns bumped from ^9.0.13 to ^9.0.14 + * @libp2p/mplex bumped from ^9.0.11 to ^9.0.12 + * @libp2p/tcp bumped from ^8.0.12 to ^8.0.13 + * @libp2p/websockets bumped from ^7.0.12 to ^7.0.13 + +### [0.46.19](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.18...libp2p-v0.46.19) (2023-11-07) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.10 to ^9.0.11 + * @libp2p/floodsub bumped from ^8.0.11 to ^8.0.12 + * @libp2p/interface-compliance-tests bumped from ^4.1.3 to ^4.1.4 + * @libp2p/kad-dht bumped from ^10.0.12 to ^10.0.13 + * @libp2p/mdns bumped from ^9.0.12 to ^9.0.13 + * @libp2p/mplex bumped from ^9.0.10 to ^9.0.11 + * @libp2p/tcp bumped from ^8.0.11 to ^8.0.12 + * @libp2p/websockets bumped from ^7.0.11 to ^7.0.12 + +### [0.46.18](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.17...libp2p-v0.46.18) (2023-11-06) + + +### Bug Fixes + +* append peer id to dial addresses before filtering ([#2199](https://www.github.com/libp2p/js-libp2p/issues/2199)) ([bafccd6](https://www.github.com/libp2p/js-libp2p/commit/bafccd6b8e90c2cf1c616aeeb5001ade940c523a)) +* log peer data in identify correctly ([#2197](https://www.github.com/libp2p/js-libp2p/issues/2197)) ([fdcb801](https://www.github.com/libp2p/js-libp2p/commit/fdcb801ee3180b740a25e0e05a75c32dd8e4ef63)) +* only send ip/domain observed address in identify ([#2201](https://www.github.com/libp2p/js-libp2p/issues/2201)) ([40855f4](https://www.github.com/libp2p/js-libp2p/commit/40855f4f38bf5e56ccb2890699ec0cdd60596a27)) + +### [0.46.17](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.16...libp2p-v0.46.17) (2023-11-03) + + +### Bug Fixes + +* allow dialing a peer when we only have transient connections ([#2187](https://www.github.com/libp2p/js-libp2p/issues/2187)) ([dd400cd](https://www.github.com/libp2p/js-libp2p/commit/dd400cd57bd4943469af1ffc67b235a46c2b206c)) +* append peer id to connection remote addr if not present ([#2182](https://www.github.com/libp2p/js-libp2p/issues/2182)) ([3bdaad3](https://www.github.com/libp2p/js-libp2p/commit/3bdaad3956cb015af1657f3f23061b47463953da)) +* do not overwrite addresses on identify push when none are sent ([#2192](https://www.github.com/libp2p/js-libp2p/issues/2192)) ([025c082](https://www.github.com/libp2p/js-libp2p/commit/025c082a4d3d08904f1f5b0209ed6f40648fb78d)) +* opt-in to toplogy notifications on transient connections ([#2049](https://www.github.com/libp2p/js-libp2p/issues/2049)) ([346ff5a](https://www.github.com/libp2p/js-libp2p/commit/346ff5a2b81bded9f9b26051501ab9d25246961c)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.6 to ^2.0.7 + * @libp2p/interface bumped from ^0.1.4 to ^0.1.5 + * @libp2p/interface-internal bumped from ^0.1.7 to ^0.1.8 + * @libp2p/keychain bumped from ^3.0.6 to ^3.0.7 + * @libp2p/logger bumped from ^3.0.4 to ^3.0.5 + * @libp2p/multistream-select bumped from ^4.0.4 to ^4.0.5 + * @libp2p/peer-collections bumped from ^4.0.6 to ^4.0.7 + * @libp2p/peer-id bumped from ^3.0.4 to ^3.0.5 + * @libp2p/peer-id-factory bumped from ^3.0.6 to ^3.0.7 + * @libp2p/peer-record bumped from ^6.0.7 to ^6.0.8 + * @libp2p/peer-store bumped from ^9.0.7 to ^9.0.8 + * @libp2p/utils bumped from ^4.0.5 to ^4.0.6 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.9 to ^9.0.10 + * @libp2p/floodsub bumped from ^8.0.10 to ^8.0.11 + * @libp2p/interface-compliance-tests bumped from ^4.1.2 to ^4.1.3 + * @libp2p/kad-dht bumped from ^10.0.11 to ^10.0.12 + * @libp2p/mdns bumped from ^9.0.11 to ^9.0.12 + * @libp2p/mplex bumped from ^9.0.9 to ^9.0.10 + * @libp2p/tcp bumped from ^8.0.10 to ^8.0.11 + * @libp2p/websockets bumped from ^7.0.10 to ^7.0.11 + +### [0.46.16](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.15...libp2p-v0.46.16) (2023-10-25) + + +### Bug Fixes + +* rename event emitter class ([#2173](https://www.github.com/libp2p/js-libp2p/issues/2173)) ([50f912c](https://www.github.com/libp2p/js-libp2p/commit/50f912c2608caecc09acbcb0f46b4df4af073080)) +* revert "refactor: rename event emitter class" ([#2172](https://www.github.com/libp2p/js-libp2p/issues/2172)) ([0ef5f7f](https://www.github.com/libp2p/js-libp2p/commit/0ef5f7f62d9c6d822e0a4b99cc203a1516b11f2f)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.5 to ^2.0.6 + * @libp2p/interface bumped from ^0.1.3 to ^0.1.4 + * @libp2p/interface-internal bumped from ^0.1.6 to ^0.1.7 + * @libp2p/keychain bumped from ^3.0.5 to ^3.0.6 + * @libp2p/logger bumped from ^3.0.3 to ^3.0.4 + * @libp2p/multistream-select bumped from ^4.0.3 to ^4.0.4 + * @libp2p/peer-collections bumped from ^4.0.5 to ^4.0.6 + * @libp2p/peer-id bumped from ^3.0.3 to ^3.0.4 + * @libp2p/peer-id-factory bumped from ^3.0.5 to ^3.0.6 + * @libp2p/peer-record bumped from ^6.0.6 to ^6.0.7 + * @libp2p/peer-store bumped from ^9.0.6 to ^9.0.7 + * @libp2p/utils bumped from ^4.0.4 to ^4.0.5 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.8 to ^9.0.9 + * @libp2p/floodsub bumped from ^8.0.9 to ^8.0.10 + * @libp2p/interface-compliance-tests bumped from ^4.1.1 to ^4.1.2 + * @libp2p/kad-dht bumped from ^10.0.10 to ^10.0.11 + * @libp2p/mdns bumped from ^9.0.10 to ^9.0.11 + * @libp2p/mplex bumped from ^9.0.8 to ^9.0.9 + * @libp2p/tcp bumped from ^8.0.9 to ^8.0.10 + * @libp2p/websockets bumped from ^7.0.9 to ^7.0.10 + +### [0.46.15](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.14...libp2p-v0.46.15) (2023-10-25) + + +### Bug Fixes + +* remove relay:removed event listener after relay is removed ([#1998](https://www.github.com/libp2p/js-libp2p/issues/1998)) ([ab2c1f6](https://www.github.com/libp2p/js-libp2p/commit/ab2c1f6731ccfe21a39482bdab217a8abd3f027b)) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/kad-dht bumped from ^10.0.9 to ^10.0.10 + +### [0.46.14](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.13...libp2p-v0.46.14) (2023-10-10) + + +### Bug Fixes + +* **circuit-relay:** respect applyDefaultLimit when it is false ([#2139](https://www.github.com/libp2p/js-libp2p/issues/2139)) ([df2153e](https://www.github.com/libp2p/js-libp2p/commit/df2153e268a72edd00c7663ce9d196d5547e994d)) + +### [0.46.13](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.12...libp2p-v0.46.13) (2023-10-06) + + +### Bug Fixes + +* add missing events dep to fix browser bundlers ([#2134](https://www.github.com/libp2p/js-libp2p/issues/2134)) ([f670307](https://www.github.com/libp2p/js-libp2p/commit/f670307a90fe6665f10630823dd7058aab2a1c2f)), closes [#2110](https://www.github.com/libp2p/js-libp2p/issues/2110) +* close webrtc streams without data loss ([#2073](https://www.github.com/libp2p/js-libp2p/issues/2073)) ([7d8b155](https://www.github.com/libp2p/js-libp2p/commit/7d8b15517a480e01a8ebd427ab0093509b78d5b0)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.4 to ^2.0.5 + * @libp2p/interface bumped from ^0.1.2 to ^0.1.3 + * @libp2p/interface-internal bumped from ^0.1.5 to ^0.1.6 + * @libp2p/keychain bumped from ^3.0.4 to ^3.0.5 + * @libp2p/logger bumped from ^3.0.2 to ^3.0.3 + * @libp2p/multistream-select bumped from ^4.0.2 to ^4.0.3 + * @libp2p/peer-collections bumped from ^4.0.4 to ^4.0.5 + * @libp2p/peer-id bumped from ^3.0.2 to ^3.0.3 + * @libp2p/peer-id-factory bumped from ^3.0.4 to ^3.0.5 + * @libp2p/peer-record bumped from ^6.0.5 to ^6.0.6 + * @libp2p/peer-store bumped from ^9.0.5 to ^9.0.6 + * @libp2p/utils bumped from ^4.0.3 to ^4.0.4 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.7 to ^9.0.8 + * @libp2p/floodsub bumped from ^8.0.8 to ^8.0.9 + * @libp2p/interface-compliance-tests bumped from ^4.1.0 to ^4.1.1 + * @libp2p/kad-dht bumped from ^10.0.8 to ^10.0.9 + * @libp2p/mdns bumped from ^9.0.9 to ^9.0.10 + * @libp2p/mplex bumped from ^9.0.7 to ^9.0.8 + * @libp2p/tcp bumped from ^8.0.8 to ^8.0.9 + * @libp2p/websockets bumped from ^7.0.8 to ^7.0.9 + +### [0.46.12](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.11...libp2p-v0.46.12) (2023-10-01) + + +### Bug Fixes + +* ensure all listeners are properly closed on tcp shutdown ([#2058](https://www.github.com/libp2p/js-libp2p/issues/2058)) ([b57bca4](https://www.github.com/libp2p/js-libp2p/commit/b57bca4493e1634108fe187466024e374b76c114)) +* include peer id in autodial log message ([#2075](https://www.github.com/libp2p/js-libp2p/issues/2075)) ([368ee26](https://www.github.com/libp2p/js-libp2p/commit/368ee26dbea5de8fb67d9a4596a169f327e73145)) +* **libp2p:** update circuit relay and upgrader logs ([#2071](https://www.github.com/libp2p/js-libp2p/issues/2071)) ([f09ac4a](https://www.github.com/libp2p/js-libp2p/commit/f09ac4a7704070fd92bae8d4482d06eac45ddd2c)) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.6 to ^9.0.7 + * @libp2p/floodsub bumped from ^8.0.7 to ^8.0.8 + * @libp2p/interface-compliance-tests bumped from ^4.0.6 to ^4.1.0 + * @libp2p/kad-dht bumped from ^10.0.7 to ^10.0.8 + * @libp2p/mdns bumped from ^9.0.8 to ^9.0.9 + * @libp2p/mplex bumped from ^9.0.6 to ^9.0.7 + * @libp2p/tcp bumped from ^8.0.7 to ^8.0.8 + * @libp2p/websockets bumped from ^7.0.7 to ^7.0.8 + +### [0.46.11](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.10...libp2p-v0.46.11) (2023-09-15) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.3 to ^2.0.4 + * @libp2p/interface-internal bumped from ^0.1.4 to ^0.1.5 + * @libp2p/keychain bumped from ^3.0.3 to ^3.0.4 + * @libp2p/peer-collections bumped from ^4.0.3 to ^4.0.4 + * @libp2p/peer-id-factory bumped from ^3.0.3 to ^3.0.4 + * @libp2p/peer-record bumped from ^6.0.4 to ^6.0.5 + * @libp2p/peer-store bumped from ^9.0.4 to ^9.0.5 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.5 to ^9.0.6 + * @libp2p/floodsub bumped from ^8.0.6 to ^8.0.7 + * @libp2p/interface-compliance-tests bumped from ^4.0.5 to ^4.0.6 + * @libp2p/kad-dht bumped from ^10.0.6 to ^10.0.7 + * @libp2p/mdns bumped from ^9.0.7 to ^9.0.8 + * @libp2p/mplex bumped from ^9.0.5 to ^9.0.6 + * @libp2p/tcp bumped from ^8.0.6 to ^8.0.7 + * @libp2p/websockets bumped from ^7.0.6 to ^7.0.7 + +### [0.46.9](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.8...libp2p-v0.46.9) (2023-09-05) + + +### Bug Fixes + +* **libp2p:** emit peer:discovered event on internal event bus ([#2019](https://www.github.com/libp2p/js-libp2p/issues/2019)) ([a6be8f0](https://www.github.com/libp2p/js-libp2p/commit/a6be8f0f4bbd81826c2ca5d48ea6175b1fdf3ab9)) + +### [0.46.8](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.7...libp2p-v0.46.8) (2023-09-01) + + +### Bug Fixes + +* **libp2p:** update peer store with supported protocols after unhandle ([#2013](https://www.github.com/libp2p/js-libp2p/issues/2013)) ([63041af](https://www.github.com/libp2p/js-libp2p/commit/63041afefbefd246ee1d6d6a4958b1999076dc17)) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/mdns bumped from ^9.0.5 to ^9.0.6 + +### [0.46.7](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.6...libp2p-v0.46.7) (2023-08-25) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.4 to ^9.0.5 + * @libp2p/floodsub bumped from ^8.0.5 to ^8.0.6 + * @libp2p/interface-compliance-tests bumped from ^4.0.4 to ^4.0.5 + * @libp2p/kad-dht bumped from ^10.0.4 to ^10.0.5 + * @libp2p/mdns bumped from ^9.0.4 to ^9.0.5 + * @libp2p/mplex bumped from ^9.0.4 to ^9.0.5 + * @libp2p/tcp bumped from ^8.0.4 to ^8.0.5 + * @libp2p/websockets bumped from ^7.0.4 to ^7.0.5 + +### [0.46.6](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.5...libp2p-v0.46.6) (2023-08-16) + + +### Bug Fixes + +* **libp2p:** move delay dep to production dependencies ([#1977](https://www.github.com/libp2p/js-libp2p/issues/1977)) ([725f5df](https://www.github.com/libp2p/js-libp2p/commit/725f5df1782a200cf1d12e6d03a164d028a7cc3e)) + +### [0.46.5](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.4...libp2p-v0.46.5) (2023-08-16) + + +### Features + +* **libp2p:** add autodial retry threshold config option ([#1943](https://www.github.com/libp2p/js-libp2p/issues/1943)) ([4ef9c79](https://www.github.com/libp2p/js-libp2p/commit/4ef9c79cd1705f25170467d9268b89ba18d7e2a0)) +* **libp2p:** direct connection through relay protocol (DCUtR) ([#1928](https://www.github.com/libp2p/js-libp2p/issues/1928)) ([87dc7e9](https://www.github.com/libp2p/js-libp2p/commit/87dc7e9fc17becc4b5c3ce4f3febd28cf9f25c6e)) + + +### Bug Fixes + +* **libp2p:** reduce dialer activity in browsers ([#1970](https://www.github.com/libp2p/js-libp2p/issues/1970)) ([d30f09f](https://www.github.com/libp2p/js-libp2p/commit/d30f09f29bcf34a0f1d7c7c984dad6dc34bb669a)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/interface-internal bumped from ^0.1.3 to ^0.1.4 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.3 to ^9.0.4 + * @libp2p/floodsub bumped from ^8.0.4 to ^8.0.5 + * @libp2p/interface-compliance-tests bumped from ^4.0.3 to ^4.0.4 + * @libp2p/kad-dht bumped from ^10.0.3 to ^10.0.4 + * @libp2p/mdns bumped from ^9.0.3 to ^9.0.4 + * @libp2p/mplex bumped from ^9.0.3 to ^9.0.4 + * @libp2p/tcp bumped from ^8.0.3 to ^8.0.4 + * @libp2p/websockets bumped from ^7.0.3 to ^7.0.4 + +### [0.46.4](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.3...libp2p-v0.46.4) (2023-08-14) + + +### Bug Fixes + +* **libp2p:** filter out dnsaddrs for different peers ([#1954](https://www.github.com/libp2p/js-libp2p/issues/1954)) ([a31b420](https://www.github.com/libp2p/js-libp2p/commit/a31b420f1920533d92e0aec4ddedcf323957bd44)) +* remove stream add/remove methods from connection interface ([#1912](https://www.github.com/libp2p/js-libp2p/issues/1912)) ([e26848b](https://www.github.com/libp2p/js-libp2p/commit/e26848b06e77bfcff4063139c9ed816f37f05cb6)) +* update project config ([9c0353c](https://www.github.com/libp2p/js-libp2p/commit/9c0353cf5a1e13196ca0e7764f87e36478518f69)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.2 to ^2.0.3 + * @libp2p/interface bumped from ^0.1.1 to ^0.1.2 + * @libp2p/interface-internal bumped from ^0.1.2 to ^0.1.3 + * @libp2p/keychain bumped from ^3.0.2 to ^3.0.3 + * @libp2p/logger bumped from ^3.0.1 to ^3.0.2 + * @libp2p/multistream-select bumped from ^4.0.1 to ^4.0.2 + * @libp2p/peer-collections bumped from ^4.0.2 to ^4.0.3 + * @libp2p/peer-id bumped from ^3.0.1 to ^3.0.2 + * @libp2p/peer-id-factory bumped from ^3.0.2 to ^3.0.3 + * @libp2p/peer-record bumped from ^6.0.2 to ^6.0.3 + * @libp2p/peer-store bumped from ^9.0.2 to ^9.0.3 + * @libp2p/utils bumped from ^4.0.1 to ^4.0.2 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.2 to ^9.0.3 + * @libp2p/floodsub bumped from ^8.0.3 to ^8.0.4 + * @libp2p/interface-compliance-tests bumped from ^4.0.2 to ^4.0.3 + * @libp2p/kad-dht bumped from ^10.0.2 to ^10.0.3 + * @libp2p/mdns bumped from ^9.0.2 to ^9.0.3 + * @libp2p/mplex bumped from ^9.0.2 to ^9.0.3 + * @libp2p/tcp bumped from ^8.0.2 to ^8.0.3 + * @libp2p/websockets bumped from ^7.0.2 to ^7.0.3 + +### [0.46.3](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.2...libp2p-v0.46.3) (2023-08-05) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.1 to ^2.0.2 + * @libp2p/interface bumped from ^0.1.0 to ^0.1.1 + * @libp2p/interface-internal bumped from ^0.1.1 to ^0.1.2 + * @libp2p/keychain bumped from ^3.0.1 to ^3.0.2 + * @libp2p/logger bumped from ^3.0.0 to ^3.0.1 + * @libp2p/multistream-select bumped from ^4.0.0 to ^4.0.1 + * @libp2p/peer-collections bumped from ^4.0.1 to ^4.0.2 + * @libp2p/peer-id bumped from ^3.0.0 to ^3.0.1 + * @libp2p/peer-id-factory bumped from ^3.0.1 to ^3.0.2 + * @libp2p/peer-record bumped from ^6.0.1 to ^6.0.2 + * @libp2p/peer-store bumped from ^9.0.1 to ^9.0.2 + * @libp2p/utils bumped from ^4.0.0 to ^4.0.1 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.1 to ^9.0.2 + * @libp2p/floodsub bumped from ^8.0.2 to ^8.0.3 + * @libp2p/interface-compliance-tests bumped from ^4.0.1 to ^4.0.2 + * @libp2p/kad-dht bumped from ^10.0.1 to ^10.0.2 + * @libp2p/mdns bumped from ^9.0.1 to ^9.0.2 + * @libp2p/mplex bumped from ^9.0.1 to ^9.0.2 + * @libp2p/tcp bumped from ^8.0.1 to ^8.0.2 + * @libp2p/websockets bumped from ^7.0.1 to ^7.0.2 + +### [0.46.2](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.1...libp2p-v0.46.2) (2023-08-04) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^2.0.0 to ^2.0.1 + * @libp2p/interface-internal bumped from ^0.1.0 to ^0.1.1 + * @libp2p/keychain bumped from ^3.0.0 to ^3.0.1 + * @libp2p/peer-collections bumped from ^4.0.0 to ^4.0.1 + * @libp2p/peer-id-factory bumped from ^3.0.0 to ^3.0.1 + * @libp2p/peer-record bumped from ^6.0.0 to ^6.0.1 + * @libp2p/peer-store bumped from ^9.0.0 to ^9.0.1 + * devDependencies + * @libp2p/bootstrap bumped from ^9.0.0 to ^9.0.1 + * @libp2p/floodsub bumped from ^8.0.1 to ^8.0.2 + * @libp2p/interface-compliance-tests bumped from ^4.0.0 to ^4.0.1 + * @libp2p/kad-dht bumped from ^10.0.0 to ^10.0.1 + * @libp2p/mdns bumped from ^9.0.0 to ^9.0.1 + * @libp2p/mplex bumped from ^9.0.0 to ^9.0.1 + * @libp2p/tcp bumped from ^8.0.0 to ^8.0.1 + * @libp2p/websockets bumped from ^7.0.0 to ^7.0.1 + +### [0.46.1](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.46.0...libp2p-v0.46.1) (2023-08-01) + + +### Dependencies + +* The following workspace dependencies were updated + * devDependencies + * @libp2p/floodsub bumped from ^8.0.0 to ^8.0.1 + +## [0.46.0](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.45.9...libp2p-v0.46.0) (2023-07-31) + + +### ⚠ BREAKING CHANGES + +* the `.close`, `closeRead` and `closeWrite` methods on the `Stream` interface are now asynchronous +* `stream.stat.*` and `conn.stat.*` properties are now accessed via `stream.*` and `conn.*` +* consolidate interface modules (#1833) + +### Features + +* enable manual identify ([#1784](https://www.github.com/libp2p/js-libp2p/issues/1784)) ([06f4901](https://www.github.com/libp2p/js-libp2p/commit/06f4901a367ef8e6b9f74bc9b896cdb091c31b12)) +* mark connections with limits as transient ([#1890](https://www.github.com/libp2p/js-libp2p/issues/1890)) ([a1ec46b](https://www.github.com/libp2p/js-libp2p/commit/a1ec46b5f5606b7bdf3e5b085013fb88e26439f9)) +* merge stat properties into stream/connection objects ([#1856](https://www.github.com/libp2p/js-libp2p/issues/1856)) ([e9cafd3](https://www.github.com/libp2p/js-libp2p/commit/e9cafd3d8ab0f8e0655ff44e04aa41fccc912b51)), closes [#1849](https://www.github.com/libp2p/js-libp2p/issues/1849) + + +### Bug Fixes + +* close streams gracefully ([#1864](https://www.github.com/libp2p/js-libp2p/issues/1864)) ([b36ec7f](https://www.github.com/libp2p/js-libp2p/commit/b36ec7f24e477af21cec31effc086a6c611bf271)), closes [#1793](https://www.github.com/libp2p/js-libp2p/issues/1793) [#656](https://www.github.com/libp2p/js-libp2p/issues/656) +* consolidate interface modules ([#1833](https://www.github.com/libp2p/js-libp2p/issues/1833)) ([4255b1e](https://www.github.com/libp2p/js-libp2p/commit/4255b1e2485d31e00c33efa029b6426246ea23e3)) +* ignore peers with invalid multiaddrs ([#1902](https://www.github.com/libp2p/js-libp2p/issues/1902)) ([a41d25d](https://www.github.com/libp2p/js-libp2p/commit/a41d25d49696febd7fd903bbdcc95ebaeb5d4b35)) +* remove redundant nat-api override ([#1906](https://www.github.com/libp2p/js-libp2p/issues/1906)) ([1f7e18b](https://www.github.com/libp2p/js-libp2p/commit/1f7e18b07094046f10df89a1c6eab505d4c13225)) +* updated multiaddr logging ([#1797](https://www.github.com/libp2p/js-libp2p/issues/1797)) ([f427cfc](https://www.github.com/libp2p/js-libp2p/commit/f427cfc923a4bf9fd328386897a0e7181969c854)) + + +### Dependencies + +* The following workspace dependencies were updated + * dependencies + * @libp2p/crypto bumped from ^1.0.0 to ^2.0.0 + * @libp2p/interface bumped from ~0.0.1 to ^0.1.0 + * @libp2p/interface-internal bumped from ~0.0.1 to ^0.1.0 + * @libp2p/keychain bumped from ^2.0.0 to ^3.0.0 + * @libp2p/logger bumped from ^2.0.0 to ^3.0.0 + * @libp2p/multistream-select bumped from ^3.0.0 to ^4.0.0 + * @libp2p/peer-collections bumped from ^3.0.0 to ^4.0.0 + * @libp2p/peer-id bumped from ^2.0.0 to ^3.0.0 + * @libp2p/peer-id-factory bumped from ^2.0.0 to ^3.0.0 + * @libp2p/peer-record bumped from ^5.0.0 to ^6.0.0 + * @libp2p/peer-store bumped from ^8.0.0 to ^9.0.0 + * @libp2p/utils bumped from ^3.0.0 to ^4.0.0 + * devDependencies + * @libp2p/bootstrap bumped from ^8.0.0 to ^9.0.0 + * @libp2p/interface-compliance-tests bumped from ^3.0.0 to ^4.0.0 + * @libp2p/kad-dht bumped from ^9.0.0 to ^10.0.0 + * @libp2p/mdns bumped from ^8.0.0 to ^9.0.0 + * @libp2p/mplex bumped from ^8.0.0 to ^9.0.0 + * @libp2p/tcp bumped from ^7.0.0 to ^8.0.0 + * @libp2p/websockets bumped from ^6.0.0 to ^7.0.0 + +### [0.45.9](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.45.8...libp2p-v0.45.9) (2023-06-14) + + +### Bug Fixes + +* allow specifiying maxOutboundStreams in connection.newStream ([#1817](https://www.github.com/libp2p/js-libp2p/issues/1817)) ([b348fba](https://www.github.com/libp2p/js-libp2p/commit/b348fbaa7e16fd40f9a93e83a92c8152ad9e97e9)) + +### [0.45.8](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.45.7...libp2p-v0.45.8) (2023-06-14) + + +### Bug Fixes + +* expose config for max inbound/outbound stop streams ([#1812](https://www.github.com/libp2p/js-libp2p/issues/1812)) ([0828dd9](https://www.github.com/libp2p/js-libp2p/commit/0828dd9167d0d1bd6218c7554fb9239f6fb0c19d)) + +### [0.45.7](https://www.github.com/libp2p/js-libp2p/compare/libp2p-v0.45.6...libp2p-v0.45.7) (2023-06-14) + + +### Bug Fixes + +* expose config for max inbound/outbound stop streams ([#1812](https://www.github.com/libp2p/js-libp2p/issues/1812)) ([0828dd9](https://www.github.com/libp2p/js-libp2p/commit/0828dd9167d0d1bd6218c7554fb9239f6fb0c19d)) + +### [0.45.6](https://www.github.com/libp2p/js-libp2p/compare/v0.45.5...v0.45.6) (2023-06-13) + + +### Bug Fixes + +* do not allow autodial to run in parallel ([#1804](https://www.github.com/libp2p/js-libp2p/issues/1804)) ([775f892](https://www.github.com/libp2p/js-libp2p/commit/775f89283a08683c1b46811af3c1974f53abd30d)) + +### [0.45.5](https://www.github.com/libp2p/js-libp2p/compare/v0.45.4...v0.45.5) (2023-06-05) + + +### Bug Fixes + +* store unsigned identify data when signed peer record is missing ([#1790](https://www.github.com/libp2p/js-libp2p/issues/1790)) ([142ba4f](https://www.github.com/libp2p/js-libp2p/commit/142ba4fcf72fd109331eb253a4e5359eaebfed7a)) + +### [0.45.4](https://www.github.com/libp2p/js-libp2p/compare/v0.45.3...v0.45.4) (2023-05-25) + + +### Bug Fixes + +* use peer events in registrar ([#1773](https://www.github.com/libp2p/js-libp2p/issues/1773)) ([efffa70](https://www.github.com/libp2p/js-libp2p/commit/efffa7037d01350d97b3092a66fab3c7101ee71f)) + +### [0.45.3](https://www.github.com/libp2p/js-libp2p/compare/v0.45.2...v0.45.3) (2023-05-22) + + +### Bug Fixes + +* import path for interfaces module ([#1768](https://www.github.com/libp2p/js-libp2p/issues/1768)) ([8060182](https://www.github.com/libp2p/js-libp2p/commit/8060182ecd75f376c0c85d21dc50658044fae56d)) + +### [0.45.2](https://www.github.com/libp2p/js-libp2p/compare/v0.45.1...v0.45.2) (2023-05-19) + + +### Bug Fixes + +* add start/stop events ([#1766](https://www.github.com/libp2p/js-libp2p/issues/1766)) ([98fb4bc](https://www.github.com/libp2p/js-libp2p/commit/98fb4bc1dd865f984565eddbeb479c9013e7098c)) +* update autonat logging ([#1765](https://www.github.com/libp2p/js-libp2p/issues/1765)) ([3c925ff](https://www.github.com/libp2p/js-libp2p/commit/3c925ffac6390eff90762639f0f28608f6eab9b8)) + +### [0.45.1](https://www.github.com/libp2p/js-libp2p/compare/v0.45.0...v0.45.1) (2023-05-18) + + +### Bug Fixes + +* close circuit-relay streams on connection failure ([#1758](https://www.github.com/libp2p/js-libp2p/issues/1758)) ([1af7808](https://www.github.com/libp2p/js-libp2p/commit/1af7808e3fd548a9ea4bf05b97189e40f3ac5b8f)) +* do not require connection encrypters ([#1752](https://www.github.com/libp2p/js-libp2p/issues/1752)) ([2417cda](https://www.github.com/libp2p/js-libp2p/commit/2417cda57b2d2a2888a7c79066c597243c598032)) +* retain peer metadata after identify ([#1749](https://www.github.com/libp2p/js-libp2p/issues/1749)) ([752db6d](https://www.github.com/libp2p/js-libp2p/commit/752db6d6d4196de89d6efeba52404ad308926aec)) +* trace happy path connection count message ([#1754](https://www.github.com/libp2p/js-libp2p/issues/1754)) ([710da91](https://www.github.com/libp2p/js-libp2p/commit/710da918a89b6f6ee5d03c0d14a311efd40a1b8f)) + +## [0.45.0](https://www.github.com/libp2p/js-libp2p/compare/v0.44.0...v0.45.0) (2023-05-09) + + +### ⚠ BREAKING CHANGES + +* remove peer refresh (#1731) +* browsers will no longer try to dial private addresses by default +* bump it-stream-types from 1.0.5 to 2.0.1 (#1674) + +### Features + +* add event bus ([#1693](https://www.github.com/libp2p/js-libp2p/issues/1693)) ([17eb162](https://www.github.com/libp2p/js-libp2p/commit/17eb162a833a752bcf18b12244d9f68e95bc2e5d)) +* add support for arbitrary service modules ([#1563](https://www.github.com/libp2p/js-libp2p/issues/1563)) ([53b1645](https://www.github.com/libp2p/js-libp2p/commit/53b1645cf505986ccdfe33d83354d1e95f1978de)) +* emit peer:identify event after identify completes ([#1741](https://www.github.com/libp2p/js-libp2p/issues/1741)) ([cd67b7d](https://www.github.com/libp2p/js-libp2p/commit/cd67b7d884721b18458f86eabba4498f4f9e0c1f)) + + +### Bug Fixes + +* build after updating version.ts ([#1742](https://www.github.com/libp2p/js-libp2p/issues/1742)) ([1180eb0](https://www.github.com/libp2p/js-libp2p/commit/1180eb0a84fb60daa3d903aedf9585093ebc3b16)) +* clear signal to avoid memory leaks ([#1728](https://www.github.com/libp2p/js-libp2p/issues/1728)) ([5c643c3](https://www.github.com/libp2p/js-libp2p/commit/5c643c3d8dfe346c64e3e966f4b16f7b226f7c2a)) +* do not auto-dial connected peers ([#1730](https://www.github.com/libp2p/js-libp2p/issues/1730)) ([94df577](https://www.github.com/libp2p/js-libp2p/commit/94df5778a977e9bb7d6cb7c1fdaf6b25690c254f)) +* do not auto-dial peers in the dial queue ([#1740](https://www.github.com/libp2p/js-libp2p/issues/1740)) ([124ca8a](https://www.github.com/libp2p/js-libp2p/commit/124ca8a9c25d3d462edd183cbcc0a89cb8248dd6)) +* do not dial private addresses in browsers ([#1735](https://www.github.com/libp2p/js-libp2p/issues/1735)) ([e3deaa4](https://www.github.com/libp2p/js-libp2p/commit/e3deaa40584b2d0cd084f95f953bd19db2493f19)) +* increase dial queue shutdown controller signal max listeners ([#1739](https://www.github.com/libp2p/js-libp2p/issues/1739)) ([ed2fa79](https://www.github.com/libp2p/js-libp2p/commit/ed2fa794ca442b601fead50a787af53c2e8719ef)) +* listen on circuit relay addresses that contain unsupported segments ([#1732](https://www.github.com/libp2p/js-libp2p/issues/1732)) ([947639f](https://www.github.com/libp2p/js-libp2p/commit/947639f58e581fb1939b5525cf704d5ee610cc76)) +* make address manager responsible for addresses ([#1743](https://www.github.com/libp2p/js-libp2p/issues/1743)) ([ef7a5f6](https://www.github.com/libp2p/js-libp2p/commit/ef7a5f676b6428129887cfabc1ba0f3c5afd000d)) +* Refactor `Upgrader` connection gating ([#1622](https://www.github.com/libp2p/js-libp2p/issues/1622)) ([ba47c95](https://www.github.com/libp2p/js-libp2p/commit/ba47c957956e52a35d342527561e3117dd46bdd3)) +* remove autodial log line ([#1692](https://www.github.com/libp2p/js-libp2p/issues/1692)) ([102d4c2](https://www.github.com/libp2p/js-libp2p/commit/102d4c209bd7a33641e352dbd250da7ba74b6f36)) +* remove closed listeners from transport manager ([#1733](https://www.github.com/libp2p/js-libp2p/issues/1733)) ([c6367e0](https://www.github.com/libp2p/js-libp2p/commit/c6367e0bbb076c9c4470d15301754c80176c24b0)) +* remove peer refresh ([#1731](https://www.github.com/libp2p/js-libp2p/issues/1731)) ([0d46c78](https://www.github.com/libp2p/js-libp2p/commit/0d46c78fe7ca9851aada8d5e1c7af549bca7fbdb)) +* update autonat and upnp-nat services to match fetch etc ([#1729](https://www.github.com/libp2p/js-libp2p/issues/1729)) ([2c3b64a](https://www.github.com/libp2p/js-libp2p/commit/2c3b64ad3833ea1097ea2b0008aa7292aa9e4998)) + + +### deps + +* bump it-stream-types from 1.0.5 to 2.0.1 ([#1674](https://www.github.com/libp2p/js-libp2p/issues/1674)) ([6f01811](https://www.github.com/libp2p/js-libp2p/commit/6f0181189bc0508fcf51c4b382ff4cd24f5bb7b0)) + +## [0.44.0](https://www.github.com/libp2p/js-libp2p/compare/v0.43.4...v0.44.0) (2023-04-14) + + +### ⚠ BREAKING CHANGES + +* Refactors the connection manager. + +### Bug Fixes + +* encapsulate /p2p-circuit multiaddrs when dialing a known peerid ([#1680](https://www.github.com/libp2p/js-libp2p/issues/1680)) ([4078082](https://www.github.com/libp2p/js-libp2p/commit/4078082dac944c6feb64e9e45e5275d7f0bf6ae4)) +* refactor connection manager to use a prioritized queue ([#1678](https://www.github.com/libp2p/js-libp2p/issues/1678)) ([4c02e48](https://www.github.com/libp2p/js-libp2p/commit/4c02e485f1a81f6ead7f7c9a982537ce0ab84d6e)) + +### [0.43.4](https://www.github.com/libp2p/js-libp2p/compare/v0.43.3...v0.43.4) (2023-04-05) + + +### Features + +* support batch dialling ([#1623](https://www.github.com/libp2p/js-libp2p/issues/1623)) ([290e610](https://www.github.com/libp2p/js-libp2p/commit/290e6103f2497b2a74a8964b7479636c391df2ba)) + + +### Bug Fixes + +* **content-routing:utils:** improve requirePeers error msg ([#1647](https://www.github.com/libp2p/js-libp2p/issues/1647)) ([34e451a](https://www.github.com/libp2p/js-libp2p/commit/34e451afdfcc57dda2896b22d43b3e6b99b1b4cd)) +* correct a typo in an error message in AutoDialler ([#1667](https://www.github.com/libp2p/js-libp2p/issues/1667)) ([f4c99d9](https://www.github.com/libp2p/js-libp2p/commit/f4c99d95a0f1b142f6bd3e55ce930b1b776fd64a)) +* ensure to check for Infinity in checkMaxLimit function ([#1666](https://www.github.com/libp2p/js-libp2p/issues/1666)) ([00a7783](https://www.github.com/libp2p/js-libp2p/commit/00a77831b224b8d52a8d36027a8f59bfd6473d50)) +* update exports path for circuit relay ([#1676](https://www.github.com/libp2p/js-libp2p/issues/1676)) ([206b469](https://www.github.com/libp2p/js-libp2p/commit/206b469bef101f222d53f51fc15979ba965555c5)), closes [#1655](https://www.github.com/libp2p/js-libp2p/issues/1655) + +### [0.43.3](https://www.github.com/libp2p/js-libp2p/compare/v0.43.2...v0.43.3) (2023-03-28) + + +### Bug Fixes + +* add logging around filtered addresses ([#1651](https://www.github.com/libp2p/js-libp2p/issues/1651)) ([1e85114](https://www.github.com/libp2p/js-libp2p/commit/1e851148f268e10af77c1c298054a83841673610)) +* do not overwrite code property on error ([#1650](https://www.github.com/libp2p/js-libp2p/issues/1650)) ([d53ec6c](https://www.github.com/libp2p/js-libp2p/commit/d53ec6c15309e280e0ab7575633e3e03eca57bb6)) +* if available, append target peer id to address book multiaddrs ([#1649](https://www.github.com/libp2p/js-libp2p/issues/1649)) ([9aaa5f3](https://www.github.com/libp2p/js-libp2p/commit/9aaa5f3cf257a2cf24321596e206f13c164965b7)) +* remove duplicated peer id logic ([#1653](https://www.github.com/libp2p/js-libp2p/issues/1653)) ([0c9f90c](https://www.github.com/libp2p/js-libp2p/commit/0c9f90cce3ccfd5319596fbd1a6937d67cd0606d)) + +### [0.43.2](https://www.github.com/libp2p/js-libp2p/compare/v0.43.1...v0.43.2) (2023-03-21) + + +### Bug Fixes + +* Connections to Allow list peers will not be pruned ([#1564](https://www.github.com/libp2p/js-libp2p/issues/1564)) ([f9e5450](https://www.github.com/libp2p/js-libp2p/commit/f9e5450ab1721481360805d72da85bd13906a171)), closes [#1515](https://www.github.com/libp2p/js-libp2p/issues/1515) +* return relay reservations in seconds ([#1641](https://www.github.com/libp2p/js-libp2p/issues/1641)) ([78cb192](https://www.github.com/libp2p/js-libp2p/commit/78cb1925c5fb74c313247f50ace707064dcf9737)) + +### [0.43.1](https://www.github.com/libp2p/js-libp2p/compare/v0.43.0...v0.43.1) (2023-03-21) + + +### Bug Fixes + +* interpret circuit relay expiry as seconds ([#1636](https://www.github.com/libp2p/js-libp2p/issues/1636)) ([5de0f07](https://www.github.com/libp2p/js-libp2p/commit/5de0f07000f102f6e02fe6c93630581fa03a2fa7)) + +## [0.43.0](https://www.github.com/libp2p/js-libp2p/compare/v0.42.2...v0.43.0) (2023-03-17) + + +### ⚠ BREAKING CHANGES + +* the `autoDial` option has been removed from the connection manager, please see the upgrade guide +* requires an instance of `interface-datastore@8.x.x` + +### Features + +* add autonat support ([#1298](https://www.github.com/libp2p/js-libp2p/issues/1298)) ([d6c8601](https://www.github.com/libp2p/js-libp2p/commit/d6c86015b537bd853909c43cd2243cc1d3132455)), closes [#1005](https://www.github.com/libp2p/js-libp2p/issues/1005) +* implement circuit v2 ([#1533](https://www.github.com/libp2p/js-libp2p/issues/1533)) ([d605cbe](https://www.github.com/libp2p/js-libp2p/commit/d605cbe318d2b2461011181c36659d9e9108b7f4)) +* updated connection manager and dialer with new interface methods ([#1586](https://www.github.com/libp2p/js-libp2p/issues/1586)) ([f6f73a2](https://www.github.com/libp2p/js-libp2p/commit/f6f73a21ebf15d1811fb95cc3972f950c0f52789)) + + +### Bug Fixes + +* accept two incoming PING streams per peer ([#1617](https://www.github.com/libp2p/js-libp2p/issues/1617)) ([afaee4c](https://www.github.com/libp2p/js-libp2p/commit/afaee4c3e11c5c66da52afc1c0c40f1d55f02928)) +* circuit relay v2 follow up items ([#1619](https://www.github.com/libp2p/js-libp2p/issues/1619)) ([b085562](https://www.github.com/libp2p/js-libp2p/commit/b0855622a760f96c34c12d262d94514834521ffe)), closes [#1608](https://www.github.com/libp2p/js-libp2p/issues/1608) [#1610](https://www.github.com/libp2p/js-libp2p/issues/1610) +* exclude peers without multiaddrs from auto dial ([#1568](https://www.github.com/libp2p/js-libp2p/issues/1568)) ([e12202e](https://www.github.com/libp2p/js-libp2p/commit/e12202e9236c4cacb10938c1101563f4c7cf580c)) +* remove connection manager autodial option ([#1626](https://www.github.com/libp2p/js-libp2p/issues/1626)) ([da3526c](https://www.github.com/libp2p/js-libp2p/commit/da3526c000147c67addc2ea0b86c7806adf61536)) +* remove p-settle dependency, use Promise.allSettled instead ([#1593](https://www.github.com/libp2p/js-libp2p/issues/1593)) ([6e47308](https://www.github.com/libp2p/js-libp2p/commit/6e47308d89f17ee9a92f486f237aeeb01f309a81)) +* use @libp2p/keychain module instead of bundling source code ([#1569](https://www.github.com/libp2p/js-libp2p/issues/1569)) ([c02e1bd](https://www.github.com/libp2p/js-libp2p/commit/c02e1bd4982feb2d69021abc54c1603c01291867)) + + +### deps + +* update interface datastore ([#1625](https://www.github.com/libp2p/js-libp2p/issues/1625)) ([064035e](https://www.github.com/libp2p/js-libp2p/commit/064035eb2366f610866644c3be6ffb09db6f5da6)) + +### [0.42.2](https://www.github.com/libp2p/js-libp2p/compare/v0.42.1...v0.42.2) (2023-01-17) + + +### Bug Fixes + +* allow configuring circuit stream limits ([#1542](https://www.github.com/libp2p/js-libp2p/issues/1542)) ([f82e6b8](https://www.github.com/libp2p/js-libp2p/commit/f82e6b86e375b86e71cd339660a348ecba4bf68d)) +* allow dialing multiaddrs without peer ids ([#1548](https://www.github.com/libp2p/js-libp2p/issues/1548)) ([398e231](https://www.github.com/libp2p/js-libp2p/commit/398e231337c3db1ccd5b4254fb18ab1903aa68b2)) +* allow exporting PeerIds from the keychain ([#1546](https://www.github.com/libp2p/js-libp2p/issues/1546)) ([141e072](https://www.github.com/libp2p/js-libp2p/commit/141e0722ee2cd92b2b928767710de7443b5a4c56)) +* allow reading PeerId from keychain ([#1552](https://www.github.com/libp2p/js-libp2p/issues/1552)) ([0831cd9](https://www.github.com/libp2p/js-libp2p/commit/0831cd960d423545ee60b457d66a6a996888804b)) +* do not append peer id to path addresses ([#1547](https://www.github.com/libp2p/js-libp2p/issues/1547)) ([bd2bdf7](https://www.github.com/libp2p/js-libp2p/commit/bd2bdf7ca0d87ab63b2e9acf7edf7a5752e0559c)) +* improve pubsub example ([#1549](https://www.github.com/libp2p/js-libp2p/issues/1549)) ([ba8527c](https://www.github.com/libp2p/js-libp2p/commit/ba8527c317b9f1f31f5066b6204fda35d393058f)) + +### [0.42.1](https://www.github.com/libp2p/js-libp2p/compare/v0.42.0...v0.42.1) (2023-01-11) + + +### Bug Fixes + +* update ci files to publish docs ([a61e401](https://www.github.com/libp2p/js-libp2p/commit/a61e40142f1393c53b83a1b11ded6b72c6b76615)) + +## [0.42.0](https://www.github.com/libp2p/js-libp2p/compare/v0.41.0...v0.42.0) (2023-01-10) + + +### ⚠ BREAKING CHANGES + +* update multiformats (#1535) +* the `FaultTolerance` enum should now be imported from `@libp2p/interface-transport` +* the connection manager and registrar are internal types and as such not part of the libp2p interface, instead use the methods exposed on the root libp2p type for obtaining connections and protocols (see the upgrade guide) + +### Bug Fixes + +* add getProtocols method ([#1523](https://www.github.com/libp2p/js-libp2p/issues/1523)) ([57a56aa](https://www.github.com/libp2p/js-libp2p/commit/57a56aa9d32f81066667ad6641fda5980df8e1c3)) +* add register and unregister methods to root node object ([#1536](https://www.github.com/libp2p/js-libp2p/issues/1536)) ([bdf53ae](https://www.github.com/libp2p/js-libp2p/commit/bdf53ae0d8fcca93f20e6e3d22669aa725dcac70)) +* close short-lived connections first when pruning by tag value ([#1517](https://www.github.com/libp2p/js-libp2p/issues/1517)) ([40fe372](https://www.github.com/libp2p/js-libp2p/commit/40fe3725c5733fc2cb5072b7ad09858724f8d870)), closes [#1509](https://www.github.com/libp2p/js-libp2p/issues/1509) +* expose identify service properties ([#1529](https://www.github.com/libp2p/js-libp2p/issues/1529)) ([43d0bc6](https://www.github.com/libp2p/js-libp2p/commit/43d0bc6c63eedbc72805d29aacb1378e43910dbf)) +* forward connection manager events on and update types ([#1524](https://www.github.com/libp2p/js-libp2p/issues/1524)) ([58cc480](https://www.github.com/libp2p/js-libp2p/commit/58cc4804827cae92a2fff3babb1201099577f671)) +* only configure the latency monitor if a limit is configured ([#1527](https://www.github.com/libp2p/js-libp2p/issues/1527)) ([1147550](https://www.github.com/libp2p/js-libp2p/commit/114755019b6c4d8ffe12ca6822c66fc46d9834e7)) +* remove transport manager from exports map ([#1525](https://www.github.com/libp2p/js-libp2p/issues/1525)) ([d77405c](https://www.github.com/libp2p/js-libp2p/commit/d77405c52f331a85325c0d24ef86874b2f5c4cd4)) +* revert config changes from [#1520](https://www.github.com/libp2p/js-libp2p/issues/1520) ([#1522](https://www.github.com/libp2p/js-libp2p/issues/1522)) ([2fa2893](https://www.github.com/libp2p/js-libp2p/commit/2fa28931025ffb93d985dad1269165f81709c048)) +* update docs ([#1520](https://www.github.com/libp2p/js-libp2p/issues/1520)) ([3e53c19](https://www.github.com/libp2p/js-libp2p/commit/3e53c199349ab99deeb745baff92c3aaa7647ca8)) +* update multiformats ([#1535](https://www.github.com/libp2p/js-libp2p/issues/1535)) ([ea8f279](https://www.github.com/libp2p/js-libp2p/commit/ea8f279d4f80f1986e53fb83637ac9852d50d8d4)) + +## [0.41.0](https://www.github.com/libp2p/js-libp2p/compare/v0.40.0...v0.41.0) (2022-12-06) + + +### ⚠ BREAKING CHANGES + +* libp2p.hangUp and libp2p.fetch require PeerId or Multiaddr objects the same as other methods +* the libp2p opts have changed to accept a metrics object factory function instead of a config object + +### Features + +* allow skipping upgrade steps for incoming connections ([#1502](https://www.github.com/libp2p/js-libp2p/issues/1502)) ([987c738](https://www.github.com/libp2p/js-libp2p/commit/987c7383a8493e89ccb9f91120940b1383334f1a)) +* configure metrics implementation as a module instead of shipping a built-in version ([#1471](https://www.github.com/libp2p/js-libp2p/issues/1471)) ([5e9dcf3](https://www.github.com/libp2p/js-libp2p/commit/5e9dcf3d404a975d01ee7171305cc2ab07ea7307)) +* start libp2p nodes by default ([#1500](https://www.github.com/libp2p/js-libp2p/issues/1500)) ([61fcc0b](https://www.github.com/libp2p/js-libp2p/commit/61fcc0b688214d3f8c84bc68bd6192738ae0fdfd)), closes [#1499](https://www.github.com/libp2p/js-libp2p/issues/1499) + + +### Bug Fixes + +* allow listening on duplicate addresses ([#1472](https://www.github.com/libp2p/js-libp2p/issues/1472)) ([030dbc8](https://www.github.com/libp2p/js-libp2p/commit/030dbc81a8743b98bbc0542bd40aece099ed44f6)) +* dialling duplicated addresses ([#1489](https://www.github.com/libp2p/js-libp2p/issues/1489)) ([9fd58c8](https://www.github.com/libp2p/js-libp2p/commit/9fd58c84b963ae3ad021e0ec1d864105b1613f46)), closes [#1409](https://www.github.com/libp2p/js-libp2p/issues/1409) +* pipe muxer/connection input/output streams in parallel ([#1491](https://www.github.com/libp2p/js-libp2p/issues/1491)) ([fb5fa3d](https://www.github.com/libp2p/js-libp2p/commit/fb5fa3d5b84e21c6e26407df7eb323d68038fe5d)), closes [#1342](https://www.github.com/libp2p/js-libp2p/issues/1342) +* registrar is not calling topology on peer reconnect ([#1504](https://www.github.com/libp2p/js-libp2p/issues/1504)) ([5a62f4f](https://www.github.com/libp2p/js-libp2p/commit/5a62f4f22f3d9658ae7356568283d443a76df4ea)), closes [#1496](https://www.github.com/libp2p/js-libp2p/issues/1496) +* remove strings from fetch and hangUp ([#1495](https://www.github.com/libp2p/js-libp2p/issues/1495)) ([bae32ba](https://www.github.com/libp2p/js-libp2p/commit/bae32bafce75a3801a7a96f77a9ccf43b3208f9c)) +* when passed a multiaddr, only dial that multiaddr ([#1498](https://www.github.com/libp2p/js-libp2p/issues/1498)) ([d01c37e](https://www.github.com/libp2p/js-libp2p/commit/d01c37e80fe18ca7f5752cdddc3a4415a8eb6471)) + +## [0.40.0](https://www.github.com/libp2p/js-libp2p/compare/v0.39.5...v0.40.0) (2022-10-17) + + +### ⚠ BREAKING CHANGES + +* modules no longer implement `Initializable` instead switching to constructor injection +* the old behavior was to dial any peer we discover, now we just add them to the peer store instead + +### Features + +* allow skipping encryption and custom muxer factory in upgrader ([#1411](https://www.github.com/libp2p/js-libp2p/issues/1411)) ([6615efa](https://www.github.com/libp2p/js-libp2p/commit/6615efa683f55425f90c70815467ec5ddfed1fcb)) +* deny incoming connections and add allow/deny lists ([#1398](https://www.github.com/libp2p/js-libp2p/issues/1398)) ([c185ef5](https://www.github.com/libp2p/js-libp2p/commit/c185ef549f599510f258d5d67883f7062c1c944b)) + + +### Bug Fixes + +* add after upgrade inbound method ([#1422](https://www.github.com/libp2p/js-libp2p/issues/1422)) ([487b942](https://www.github.com/libp2p/js-libp2p/commit/487b94240e244e31ebadb2f8229c1465717454eb)) +* add pending connection limit ([#1423](https://www.github.com/libp2p/js-libp2p/issues/1423)) ([b717beb](https://www.github.com/libp2p/js-libp2p/commit/b717bebf6db1483fc52595a2a137685162d29dca)) +* close stream after sending identify ([#1424](https://www.github.com/libp2p/js-libp2p/issues/1424)) ([a74d22a](https://www.github.com/libp2p/js-libp2p/commit/a74d22a2cddf9ffdca26447fe21a62b5d13e773d)) +* do not auto-dial peers ([#1397](https://www.github.com/libp2p/js-libp2p/issues/1397)) ([ca30192](https://www.github.com/libp2p/js-libp2p/commit/ca3019283497040314603d9ca7c0b65c64d1680c)) +* enable identify service all the time ([#1440](https://www.github.com/libp2p/js-libp2p/issues/1440)) ([931e042](https://www.github.com/libp2p/js-libp2p/commit/931e042228d286dfc604f91951316b83fa1734f3)) +* regenerate protobuf defs ([#1439](https://www.github.com/libp2p/js-libp2p/issues/1439)) ([e10eea2](https://www.github.com/libp2p/js-libp2p/commit/e10eea24d40243c12584429a3b3012488f82bd00)) +* remove @libp2p/components ([#1427](https://www.github.com/libp2p/js-libp2p/issues/1427)) ([a3847f2](https://www.github.com/libp2p/js-libp2p/commit/a3847f2d1725b1c92d5e0ef7bcdf840ea8428a75)) + +### [0.39.5](https://www.github.com/libp2p/js-libp2p/compare/v0.39.4...v0.39.5) (2022-10-05) + + +### Bug Fixes + +* stub new connection manager accept incoming connection method ([#1404](https://www.github.com/libp2p/js-libp2p/issues/1404)) ([5ad175c](https://www.github.com/libp2p/js-libp2p/commit/5ad175cb3918da0956f6c1c336f5423a551c78a8)) + +### [0.39.4](https://www.github.com/libp2p/js-libp2p/compare/v0.39.3...v0.39.4) (2022-10-04) + + +### Bug Fixes + +* update insecure connection encrypter ([#1400](https://www.github.com/libp2p/js-libp2p/issues/1400)) ([12a2c75](https://www.github.com/libp2p/js-libp2p/commit/12a2c75efc0fc730976652b3ead79f8332476149)) + +### [0.39.3](https://www.github.com/libp2p/js-libp2p/compare/v0.39.2...v0.39.3) (2022-09-28) + + +### Bug Fixes + +* when creating dial targets, encapsulate PeerIds last ([#1389](https://www.github.com/libp2p/js-libp2p/issues/1389)) ([ec02351](https://www.github.com/libp2p/js-libp2p/commit/ec02351e65d0627872e6a53894c060a593b9e66e)) +* yield only final peers from dht getClosestPeers ([#1380](https://www.github.com/libp2p/js-libp2p/issues/1380)) ([3f57eda](https://www.github.com/libp2p/js-libp2p/commit/3f57edaf3b472daf8ea6e914f38ff9ad6cf9b49c)) + +### [0.39.2](https://www.github.com/libp2p/js-libp2p/compare/v0.39.1...v0.39.2) (2022-09-21) + + +### Bug Fixes + +* remove ipfs dependency and upgrade multiaddr ([#1387](https://www.github.com/libp2p/js-libp2p/issues/1387)) ([633d4a9](https://www.github.com/libp2p/js-libp2p/commit/633d4a9740ea02e32c0bb290c0a3958b68f181e9)) + +### [0.39.1](https://www.github.com/libp2p/js-libp2p/compare/v0.39.0...v0.39.1) (2022-09-09) + + +### Bug Fixes + +* add yamux interop tests ([#1290](https://www.github.com/libp2p/js-libp2p/issues/1290)) ([b87632f](https://www.github.com/libp2p/js-libp2p/commit/b87632f97f44aecf583df06aed865bc4e087391a)) +* overwrite stream fields after handshake ([#1305](https://www.github.com/libp2p/js-libp2p/issues/1305)) ([43b0418](https://www.github.com/libp2p/js-libp2p/commit/43b04189987f11a7729b522d1e1dbdc1caceb874)) +* report dialer metrics ([#1377](https://www.github.com/libp2p/js-libp2p/issues/1377)) ([0218acf](https://www.github.com/libp2p/js-libp2p/commit/0218acfae26fa69475b2ce0678b1c754c7eda605)) + +## [0.39.0](https://www.github.com/libp2p/js-libp2p/compare/v0.38.0...v0.39.0) (2022-09-05) + + +### ⚠ BREAKING CHANGES + +* the `loadKeychain` method has been removed as it is no longer necessary + +### Bug Fixes + +* discovery mechanism examples not working ([#1365](https://www.github.com/libp2p/js-libp2p/issues/1365)) ([d281a60](https://www.github.com/libp2p/js-libp2p/commit/d281a60dac973eeb0c842ffd70cd8bad3ae1156a)), closes [#1229](https://www.github.com/libp2p/js-libp2p/issues/1229) +* load self key into keychain on startup if not present ([#1357](https://www.github.com/libp2p/js-libp2p/issues/1357)) ([1f38ab7](https://www.github.com/libp2p/js-libp2p/commit/1f38ab7ac8380c9501b252d076bb356662978882)), closes [#1315](https://www.github.com/libp2p/js-libp2p/issues/1315) + +## [0.38.0](https://www.github.com/libp2p/js-libp2p/compare/v0.37.3...v0.38.0) (2022-08-17) + + +### ⚠ BREAKING CHANGES + +* Streams are now `Duplex` +* `connectionManager.peerValue` has been removed, use `peerStore.tagPeer` instead +* limit protocol streams per-connection (#1255) +* uses new single-issue libp2p interface modules + +### Features + +* limit protocol streams per-connection ([#1255](https://www.github.com/libp2p/js-libp2p/issues/1255)) ([de30c2c](https://www.github.com/libp2p/js-libp2p/commit/de30c2cec79d1e9d758cbcddc11d315b17843343)) +* programmatically set agentVersion for use in identify ([#1296](https://www.github.com/libp2p/js-libp2p/issues/1296)) ([0bb1b80](https://www.github.com/libp2p/js-libp2p/commit/0bb1b802c8fc2f32eaef10efbc88005dce6c6020)), closes [#686](https://www.github.com/libp2p/js-libp2p/issues/686) [#1240](https://www.github.com/libp2p/js-libp2p/issues/1240) +* update libp2p interfaces ([#1252](https://www.github.com/libp2p/js-libp2p/issues/1252)) ([d4dd664](https://www.github.com/libp2p/js-libp2p/commit/d4dd664071476e3d22f53e02e7d66099f3265f6c)) +* use tag values to choose which connections to close ([#1276](https://www.github.com/libp2p/js-libp2p/issues/1276)) ([b1b2b21](https://www.github.com/libp2p/js-libp2p/commit/b1b2b216daf12caccd67503dfd7b296b191c5b83)) + + +### Bug Fixes + +* add successful stream peer to protobook ([#1341](https://www.github.com/libp2p/js-libp2p/issues/1341)) ([8880eef](https://www.github.com/libp2p/js-libp2p/commit/8880eefa8ffeff1203cdf5053a17dbf45f43cc3d)) +* add timeout for circuit relay ([#1294](https://www.github.com/libp2p/js-libp2p/issues/1294)) ([ba56c64](https://www.github.com/libp2p/js-libp2p/commit/ba56c6466232ad4aa5025e2db084c5c9ccd4e5d0)) +* add timeout for incoming connections and build-in protocols ([#1292](https://www.github.com/libp2p/js-libp2p/issues/1292)) ([750ed9c](https://www.github.com/libp2p/js-libp2p/commit/750ed9c35f095aa6e136a801ccd792f2190f38a1)) +* catch errors when reconnecting old peers ([#1352](https://www.github.com/libp2p/js-libp2p/issues/1352)) ([886759b](https://www.github.com/libp2p/js-libp2p/commit/886759b7fb3c14f243d4e74b1714930424bb7453)) +* close streams when protocol limits are reached ([#1301](https://www.github.com/libp2p/js-libp2p/issues/1301)) ([3c0fb13](https://www.github.com/libp2p/js-libp2p/commit/3c0fb13babe295c8e5284345080bd4434f39efa7)) +* MaxListenersExceeded warning ([#1297](https://www.github.com/libp2p/js-libp2p/issues/1297)) ([627b8bf](https://www.github.com/libp2p/js-libp2p/commit/627b8bf87c775762dd6a9de69b77852e48ebcf26)) +* prepend connection addr to circuit relay address ([#1355](https://www.github.com/libp2p/js-libp2p/issues/1355)) ([509e56a](https://www.github.com/libp2p/js-libp2p/commit/509e56a60359f98ec435f8519c6a499641cce212)) +* remove mplex prefix from muxer errors ([#1304](https://www.github.com/libp2p/js-libp2p/issues/1304)) ([05e8e7e](https://www.github.com/libp2p/js-libp2p/commit/05e8e7ead96d494bdd7dfa5d6430155670066767)) +* specify max stream args separately ([#1254](https://www.github.com/libp2p/js-libp2p/issues/1254)) ([5371729](https://www.github.com/libp2p/js-libp2p/commit/53717296468ef17fdc3e0dda9d5908b15d2772a1)) +* update muxer behavior ([#1289](https://www.github.com/libp2p/js-libp2p/issues/1289)) ([b1b9139](https://www.github.com/libp2p/js-libp2p/commit/b1b91398e27d0b8852a74a87f0d8ccc5f34340b4)) +* use keep-alive tag to reconnect to peers on startup ([#1278](https://www.github.com/libp2p/js-libp2p/issues/1278)) ([2836acc](https://www.github.com/libp2p/js-libp2p/commit/2836acc90f8eafd2106539a80ac7d3b307c0bd02)) + + +### deps + +* update all deps to support no-copy operations ([#1335](https://www.github.com/libp2p/js-libp2p/issues/1335)) ([f439d9b](https://www.github.com/libp2p/js-libp2p/commit/f439d9b589a0a6544b61aca3736e920943ce38b5)) + +### [0.37.3](https://www.github.com/libp2p/js-libp2p/compare/v0.37.2...v0.37.3) (2022-06-08) + + +### Bug Fixes + +* connection pruning ([#1235](https://www.github.com/libp2p/js-libp2p/issues/1235)) ([f9073ec](https://www.github.com/libp2p/js-libp2p/commit/f9073ecd215e119b7a864e2ad31fe7067322c754)) +* ensure streams are closed when protocol negotiation fails ([#1236](https://www.github.com/libp2p/js-libp2p/issues/1236)) ([eee256d](https://www.github.com/libp2p/js-libp2p/commit/eee256db8ab65cea7228b1683403417edfdb1367)) +* wait for peer stats to be updated during test ([#1238](https://www.github.com/libp2p/js-libp2p/issues/1238)) ([b047268](https://www.github.com/libp2p/js-libp2p/commit/b0472686d29a4f295360d3f15a50c86c981892f7)), closes [#1219](https://www.github.com/libp2p/js-libp2p/issues/1219) + +### [0.37.2](https://www.github.com/libp2p/js-libp2p/compare/v0.37.1...v0.37.2) (2022-05-31) + + +### Bug Fixes + +* reduce identify message size limit ([#1230](https://www.github.com/libp2p/js-libp2p/issues/1230)) ([824720f](https://www.github.com/libp2p/js-libp2p/commit/824720fb8f21f868ed88e881fbc3ce6b9459600d)) + +### [0.37.1](https://www.github.com/libp2p/js-libp2p/compare/v0.37.0...v0.37.1) (2022-05-25) + + +### Bug Fixes + +* do upnp hole punch after startup ([#1217](https://www.github.com/libp2p/js-libp2p/issues/1217)) ([d5386df](https://www.github.com/libp2p/js-libp2p/commit/d5386df68478a71ac269acb2d00d36a7a5c9ebc5)) +* explicitly close streams when connnections close ([#1221](https://www.github.com/libp2p/js-libp2p/issues/1221)) ([b09eb8f](https://www.github.com/libp2p/js-libp2p/commit/b09eb8fc53ec1d8f6280d681c9ca6a467ec259b5)) +* fix unintended aborts in dialer ([#1185](https://www.github.com/libp2p/js-libp2p/issues/1185)) ([35f9c0c](https://www.github.com/libp2p/js-libp2p/commit/35f9c0c79387232465848b450a47cafe841405e7)) +* time out slow reads ([#1227](https://www.github.com/libp2p/js-libp2p/issues/1227)) ([a1220d2](https://www.github.com/libp2p/js-libp2p/commit/a1220d22f5affb64e64dec0cd6a92cd8241b26df)) + +## [0.37.0](https://www.github.com/libp2p/js-libp2p/compare/v0.36.2...v0.37.0) (2022-05-16) + + +### ⚠ BREAKING CHANGES + +* types are no longer hand crafted, this module is now ESM only + +### Features + +* convert to typescript ([#1172](https://www.github.com/libp2p/js-libp2p/issues/1172)) ([199395d](https://www.github.com/libp2p/js-libp2p/commit/199395de4d8139cc77d0b408626f37c9b8520d28)) + + +### Bug Fixes + +* add transport manager to exports map and fix docs ([#1182](https://www.github.com/libp2p/js-libp2p/issues/1182)) ([cc60cfd](https://www.github.com/libp2p/js-libp2p/commit/cc60cfde1a0907ca68f658f6de5362a708189222)) +* emit peer:connect after all ([#1171](https://www.github.com/libp2p/js-libp2p/issues/1171)) ([d16817c](https://www.github.com/libp2p/js-libp2p/commit/d16817ca443443e88803ee8096d45debb14af91b)) +* encode enums correctly ([#1210](https://www.github.com/libp2p/js-libp2p/issues/1210)) ([4837430](https://www.github.com/libp2p/js-libp2p/commit/4837430d8bcdbee0865eeba6fe694bc71fc6c9bb)) +* expose getPublicKey ([#1188](https://www.github.com/libp2p/js-libp2p/issues/1188)) ([1473044](https://www.github.com/libp2p/js-libp2p/commit/147304449e5f8d3acb8b00bdd9588b56830667c6)) +* expose metrics and registrar, use dht for peer discovery ([#1183](https://www.github.com/libp2p/js-libp2p/issues/1183)) ([64bfcee](https://www.github.com/libp2p/js-libp2p/commit/64bfcee5093b368df0b381f78afc2ddff3d339a9)) +* simplify pnet exports ([#1213](https://www.github.com/libp2p/js-libp2p/issues/1213)) ([3148060](https://www.github.com/libp2p/js-libp2p/commit/31480603f3e17d838d2685573995218a1e678e7a)) +* update deps ([#1181](https://www.github.com/libp2p/js-libp2p/issues/1181)) ([8cca8e4](https://www.github.com/libp2p/js-libp2p/commit/8cca8e4bfc6a339e58b5a5efa8a84fd891aa08ee)) +* update interfaces ([#1207](https://www.github.com/libp2p/js-libp2p/issues/1207)) ([da3d19b](https://www.github.com/libp2p/js-libp2p/commit/da3d19b30977fd2c7e77d92aa8914b13e3179aaa)) +* update pubsub interfaces ([#1194](https://www.github.com/libp2p/js-libp2p/issues/1194)) ([fab4f13](https://www.github.com/libp2p/js-libp2p/commit/fab4f1385cf61b7b16719b9aacdfe03146a3f260)) +* update to new interfaces ([#1206](https://www.github.com/libp2p/js-libp2p/issues/1206)) ([a15254f](https://www.github.com/libp2p/js-libp2p/commit/a15254fdd478a336edf1e1196b721dc56888b2ea)) +* use placeholder dht/pubsub ([#1193](https://www.github.com/libp2p/js-libp2p/issues/1193)) ([5397137](https://www.github.com/libp2p/js-libp2p/commit/5397137c654dfdec431e0c9ba4b1ff9dee19abf1)) + +### [0.36.2](https://www.github.com/libp2p/js-libp2p/compare/v0.36.1...v0.36.2) (2022-01-26) + + +### Bug Fixes + +* reject connections when not running ([#1146](https://www.github.com/libp2p/js-libp2p/issues/1146)) ([902f10d](https://www.github.com/libp2p/js-libp2p/commit/902f10d58d1062e812eb27aa0e2256e3fde5d3f6)) + +### [0.36.1](https://www.github.com/libp2p/js-libp2p/compare/v0.36.0...v0.36.1) (2022-01-25) + + +### Bug Fixes + +* await unhandle of protocols ([#1144](https://www.github.com/libp2p/js-libp2p/issues/1144)) ([d44bd90](https://www.github.com/libp2p/js-libp2p/commit/d44bd9094fe9545054eb8eff68f81bc52ece03e7)) + +## [0.36.0](https://www.github.com/libp2p/js-libp2p/compare/v0.35.8...v0.36.0) (2022-01-25) + + +### ⚠ BREAKING CHANGES + +* abort-controller dep is gone from dependency tree +* `libp2p.handle`, `libp2p.registrar.register` and the peerstore methods have become async + +### Features + +* add fetch protocol ([#1036](https://www.github.com/libp2p/js-libp2p/issues/1036)) ([d8ceb0b](https://www.github.com/libp2p/js-libp2p/commit/d8ceb0bc66fe225d1335d3f05b9a3a30983c2a57)) +* async peerstore backed by datastores ([#1058](https://www.github.com/libp2p/js-libp2p/issues/1058)) ([978eb36](https://www.github.com/libp2p/js-libp2p/commit/978eb3676fad5d5d50ddb28d1a7868f448cbb20b)) +* connection gater ([#1142](https://www.github.com/libp2p/js-libp2p/issues/1142)) ([ff32eba](https://www.github.com/libp2p/js-libp2p/commit/ff32eba6a0fa222af1a7a46775d5e0346ad6ebdf)) + + +### Bug Fixes + +* cache build artefacts ([#1091](https://www.github.com/libp2p/js-libp2p/issues/1091)) ([5043cd5](https://www.github.com/libp2p/js-libp2p/commit/5043cd56435a264e83db4fb8388d33e9a0442fff)) +* catch errors during identify ([#1138](https://www.github.com/libp2p/js-libp2p/issues/1138)) ([12f1bb0](https://www.github.com/libp2p/js-libp2p/commit/12f1bb0aeec4b639bd2af05807215f3b4284e379)) +* import uint8arrays package in example ([#1083](https://www.github.com/libp2p/js-libp2p/issues/1083)) ([c3700f5](https://www.github.com/libp2p/js-libp2p/commit/c3700f55d5a0b62182d683ca37258887b24065b9)) +* make tests more reliable ([#1139](https://www.github.com/libp2p/js-libp2p/issues/1139)) ([b7e8706](https://www.github.com/libp2p/js-libp2p/commit/b7e87066a69970f1adca4ba552c7fdf624916a7e)) +* prevent auto-dialer from dialing self ([#1104](https://www.github.com/libp2p/js-libp2p/issues/1104)) ([9b22c6e](https://www.github.com/libp2p/js-libp2p/commit/9b22c6e2f987a20c6639cd07f31fe9c824e24923)) +* remove abort-controller dep ([#1095](https://www.github.com/libp2p/js-libp2p/issues/1095)) ([0a4dc54](https://www.github.com/libp2p/js-libp2p/commit/0a4dc54d084c901df47cce1788bd5922090ee037)) +* try all peer addresses when dialing a relay ([#1140](https://www.github.com/libp2p/js-libp2p/issues/1140)) ([63aa480](https://www.github.com/libp2p/js-libp2p/commit/63aa480800974515f44d3b7e013da9c8ccaae8ad)) +* update any-signal and timeout-abort-controller ([#1128](https://www.github.com/libp2p/js-libp2p/issues/1128)) ([e0354b4](https://www.github.com/libp2p/js-libp2p/commit/e0354b4c6b95bb90656b868849182eb3efddf096)) +* update multistream select ([#1136](https://www.github.com/libp2p/js-libp2p/issues/1136)) ([00e4959](https://www.github.com/libp2p/js-libp2p/commit/00e49592a356e39b20c889d5f40b9bb37d4bf293)) +* update node-forge ([#1133](https://www.github.com/libp2p/js-libp2p/issues/1133)) ([a4bba35](https://www.github.com/libp2p/js-libp2p/commit/a4bba35948e1cd8dbe5147f2c8d6385b1fbb6fae)) + +## [0.35.8](https://github.com/libp2p/js-libp2p/compare/v0.35.7...v0.35.8) (2021-12-29) + + +### Bug Fixes + +* do not wait for autodial start ([#1089](https://github.com/libp2p/js-libp2p/issues/1089)) ([79b3cfc](https://github.com/libp2p/js-libp2p/commit/79b3cfc6ad02ecc76fe23a3c3ff2d0b32a0ae4a8)) +* increase listeners on any-signal ([#1084](https://github.com/libp2p/js-libp2p/issues/1084)) ([f18fc80](https://github.com/libp2p/js-libp2p/commit/f18fc80b70bf7b6b26fffa70b0a8d0502a6c4801)) +* look for final peer event instead of peer response ([#1092](https://github.com/libp2p/js-libp2p/issues/1092)) ([d2b7ec0](https://github.com/libp2p/js-libp2p/commit/d2b7ec0f6be0ee80f2c963279a8ec2385059a889)) +* record tracked map clears ([#1085](https://github.com/libp2p/js-libp2p/issues/1085)) ([b4b4324](https://github.com/libp2p/js-libp2p/commit/b4b432406ebc08ef2fc3a1922c64cde7c9060cae)) + + +## [0.35.7](https://github.com/libp2p/js-libp2p/compare/v0.35.2...v0.35.7) (2021-12-24) + + +### Bug Fixes + +* add tracked map ([#1069](https://github.com/libp2p/js-libp2p/issues/1069)) ([b425fa1](https://github.com/libp2p/js-libp2p/commit/b425fa12304def2a007d43a0aa445c28b766ed02)) +* clean up pending dial targets ([#1059](https://github.com/libp2p/js-libp2p/issues/1059)) ([bdc9f16](https://github.com/libp2p/js-libp2p/commit/bdc9f16d0cbe56ccf26822f11068e7795bcef046)) +* fix uncaught promise rejection when finding peers ([#1044](https://github.com/libp2p/js-libp2p/issues/1044)) ([3b683e7](https://github.com/libp2p/js-libp2p/commit/3b683e715686163e229b7b5c3a892327dfd4fc63)) +* increase the maxlisteners for timeout controllers ([#1065](https://github.com/libp2p/js-libp2p/issues/1065)) ([09a0f94](https://github.com/libp2p/js-libp2p/commit/09a0f940df7fdb4ece34604e85693709df5c213e)) +* main ci ([#1079](https://github.com/libp2p/js-libp2p/issues/1079)) ([d1c48dc](https://github.com/libp2p/js-libp2p/commit/d1c48dcbeded828f2dd3044cc9aed3f17f02846d)) +* make error codes consistent ([#1054](https://github.com/libp2p/js-libp2p/issues/1054)) ([b25e0fe](https://github.com/libp2p/js-libp2p/commit/b25e0fe5312db58a06c39500ae84c50fed3a93bd)) +* type definitions for big dialrequest and persistent peerstore ([#1078](https://github.com/libp2p/js-libp2p/issues/1078)) ([cb0d7d6](https://github.com/libp2p/js-libp2p/commit/cb0d7d6c99d179498f04e76df76e70e4f7d41c4c)) + + +### Features + +* allow per-component metrics to be collected ([#1061](https://github.com/libp2p/js-libp2p/issues/1061)) ([2f0b311](https://github.com/libp2p/js-libp2p/commit/2f0b311df7127aa44512c2008142d4ca30268986)), closes [#1060](https://github.com/libp2p/js-libp2p/issues/1060) + + + +## [0.35.6](https://github.com/libp2p/js-libp2p/compare/v0.35.5...v0.35.6) (2021-12-18) + + +### Bug Fixes + +* increase the maxlisteners for timeout controllers ([#1065](https://github.com/libp2p/js-libp2p/issues/1065)) ([09a0f94](https://github.com/libp2p/js-libp2p/commit/09a0f940df7fdb4ece34604e85693709df5c213e)) + + + +## [0.35.5](https://github.com/libp2p/js-libp2p/compare/v0.35.4...v0.35.5) (2021-12-15) + + + +## [0.35.4](https://github.com/libp2p/js-libp2p/compare/v0.35.3...v0.35.4) (2021-12-15) + + +### Features + +* allow per-component metrics to be collected ([#1061](https://github.com/libp2p/js-libp2p/issues/1061)) ([2f0b311](https://github.com/libp2p/js-libp2p/commit/2f0b311df7127aa44512c2008142d4ca30268986)), closes [#1060](https://github.com/libp2p/js-libp2p/issues/1060) + + + +## [0.35.3](https://github.com/libp2p/js-libp2p/compare/v0.35.2...v0.35.3) (2021-12-13) + + +### Bug Fixes + +* clean up pending dial targets ([#1059](https://github.com/libp2p/js-libp2p/issues/1059)) ([bdc9f16](https://github.com/libp2p/js-libp2p/commit/bdc9f16d0cbe56ccf26822f11068e7795bcef046)) +* fix uncaught promise rejection when finding peers ([#1044](https://github.com/libp2p/js-libp2p/issues/1044)) ([3b683e7](https://github.com/libp2p/js-libp2p/commit/3b683e715686163e229b7b5c3a892327dfd4fc63)) +* make error codes consistent ([#1054](https://github.com/libp2p/js-libp2p/issues/1054)) ([b25e0fe](https://github.com/libp2p/js-libp2p/commit/b25e0fe5312db58a06c39500ae84c50fed3a93bd)) + + + +## [0.35.2](https://github.com/libp2p/js-libp2p/compare/v0.33.0...v0.35.2) (2021-12-06) + + +### Bug Fixes + +* do not let closest peers run forever ([#1047](https://github.com/libp2p/js-libp2p/issues/1047)) ([91c2ec9](https://github.com/libp2p/js-libp2p/commit/91c2ec9856a3e972b7b2c9c4d9a4eda1d431c7ef)) +* increase maxlisteners on event target ([#1050](https://github.com/libp2p/js-libp2p/issues/1050)) ([b70fb43](https://github.com/libp2p/js-libp2p/commit/b70fb43427b47df079b55929ec8956f69cbda966)), closes [#900](https://github.com/libp2p/js-libp2p/issues/900) +* private ip ts compile has no call signatures ([#1020](https://github.com/libp2p/js-libp2p/issues/1020)) ([77d7cb8](https://github.com/libp2p/js-libp2p/commit/77d7cb8f0815f2cdd3bfdfa8b641a7a186fe9520)) +* stop dht before connection manager ([#1041](https://github.com/libp2p/js-libp2p/issues/1041)) ([3a9d5f6](https://github.com/libp2p/js-libp2p/commit/3a9d5f64d96719ebb4d3b083c4f5832db4fa0816)), closes [#1039](https://github.com/libp2p/js-libp2p/issues/1039) + + +### chore + +* update peer id and libp2p crypto ([#1042](https://github.com/libp2p/js-libp2p/issues/1042)) ([9cbf36f](https://github.com/libp2p/js-libp2p/commit/9cbf36fcb54099e6fed35ceccc4a2376f0926c1f)) + + +### Features + +* update dht ([#1009](https://github.com/libp2p/js-libp2p/issues/1009)) ([2f598eb](https://github.com/libp2p/js-libp2p/commit/2f598eba09cff4301474af08196158065e3602d8)) + + +### BREAKING CHANGES + +* requires node 15+ +* libp2p-kad-dht has a new event-based API which is exposed as `_dht` + + + +## [0.35.1](https://github.com/libp2p/js-libp2p/compare/v0.35.0...v0.35.1) (2021-12-03) + + +### Bug Fixes + +* do not let closest peers run forever ([#1047](https://github.com/libp2p/js-libp2p/issues/1047)) ([91c2ec9](https://github.com/libp2p/js-libp2p/commit/91c2ec9856a3e972b7b2c9c4d9a4eda1d431c7ef)) + + + +# [0.35.0](https://github.com/libp2p/js-libp2p/compare/v0.34.0...v0.35.0) (2021-12-02) + + +### Bug Fixes + +* stop dht before connection manager ([#1041](https://github.com/libp2p/js-libp2p/issues/1041)) ([3a9d5f6](https://github.com/libp2p/js-libp2p/commit/3a9d5f64d96719ebb4d3b083c4f5832db4fa0816)), closes [#1039](https://github.com/libp2p/js-libp2p/issues/1039) + + +### chore + +* update peer id and libp2p crypto ([#1042](https://github.com/libp2p/js-libp2p/issues/1042)) ([9cbf36f](https://github.com/libp2p/js-libp2p/commit/9cbf36fcb54099e6fed35ceccc4a2376f0926c1f)) + + +### BREAKING CHANGES + +* requires node 15+ + + + +# [0.34.0](https://github.com/libp2p/js-libp2p/compare/v0.33.0...v0.34.0) (2021-11-25) + + +### Bug Fixes + +* private ip ts compile has no call signatures ([#1020](https://github.com/libp2p/js-libp2p/issues/1020)) ([77d7cb8](https://github.com/libp2p/js-libp2p/commit/77d7cb8f0815f2cdd3bfdfa8b641a7a186fe9520)) + + +### Features + +* update dht ([#1009](https://github.com/libp2p/js-libp2p/issues/1009)) ([2f598eb](https://github.com/libp2p/js-libp2p/commit/2f598eba09cff4301474af08196158065e3602d8)) + + +### BREAKING CHANGES + +* libp2p-kad-dht has a new event-based API which is exposed as `_dht` + + + +# [0.33.0](https://github.com/libp2p/js-libp2p/compare/v0.32.5...v0.33.0) (2021-09-24) + + +### chore + +* update datastore ([#990](https://github.com/libp2p/js-libp2p/issues/990)) ([83734ef](https://github.com/libp2p/js-libp2p/commit/83734ef52061ad61ddb5ca49aae27e3a8b937058)) + + +### BREAKING CHANGES + +* datastore implementations provided to libp2p must be compliant with interface-datastore@6.0.0 + + + +## [0.32.5](https://github.com/libp2p/js-libp2p/compare/v0.32.4...v0.32.5) (2021-09-21) + + +### Bug Fixes + +* move abortable-iterator to dependencies ([#992](https://github.com/libp2p/js-libp2p/issues/992)) ([122c89d](https://github.com/libp2p/js-libp2p/commit/122c89dd0df55a59edaae078e3dc7c31b5603715)), closes [#986](https://github.com/libp2p/js-libp2p/issues/986) + + + +## [0.32.4](https://github.com/libp2p/js-libp2p/compare/v0.32.3...v0.32.4) (2021-08-20) + + + +## [0.32.3](https://github.com/libp2p/js-libp2p/compare/v0.32.2...v0.32.3) (2021-08-16) + + +### Bug Fixes + +* uint8arrays is a dep ([#964](https://github.com/libp2p/js-libp2p/issues/964)) ([ba2b4d4](https://github.com/libp2p/js-libp2p/commit/ba2b4d4b28f1d9940b457de344aed44537f9eabd)) + + + +## [0.32.2](https://github.com/libp2p/js-libp2p/compare/v0.32.1...v0.32.2) (2021-08-13) + + +### Bug Fixes + +* browser example ci ([3b33fb4](https://github.com/libp2p/js-libp2p/commit/3b33fb4b73ba8065e432fb59f758fe138fd23d9e)) + + +### Features + +* custom protocol name ([#962](https://github.com/libp2p/js-libp2p/issues/962)) ([ef24fab](https://github.com/libp2p/js-libp2p/commit/ef24fabf0269fd079888e92eedb458e23ef1c733)) + + + +## [0.32.1](https://github.com/libp2p/js-libp2p/compare/v0.32.0...v0.32.1) (2021-07-22) + + +### Bug Fixes + +* turn compliance tests into devDependency ([#960](https://github.com/libp2p/js-libp2p/issues/960)) ([0701de4](https://github.com/libp2p/js-libp2p/commit/0701de40b1ebdf319959846d8c4fdd30b3cf34a4)) + + + +# [0.32.0](https://github.com/libp2p/js-libp2p/compare/v0.32.0-rc.0...v0.32.0) (2021-07-15) + + + +# [0.32.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.31.7...v0.32.0-rc.0) (2021-07-09) + + +### Bug Fixes + +* do not allow dial to large number of multiaddrs ([#954](https://github.com/libp2p/js-libp2p/issues/954)) ([af723b3](https://github.com/libp2p/js-libp2p/commit/af723b355e1ddf4aecf439f81c3aa67613d45fa4)) + + +### chore + +* update to new multiformats ([#948](https://github.com/libp2p/js-libp2p/issues/948)) ([13cf476](https://github.com/libp2p/js-libp2p/commit/13cf4761489d59b22924bb8ec2ec6dbe207b280c)) + + +### BREAKING CHANGES + +* uses the CID class from the new multiformats module + +Co-authored-by: Vasco Santos + + + +## [0.31.7](https://github.com/libp2p/js-libp2p/compare/v0.31.6...v0.31.7) (2021-06-14) + + +### Bug Fixes + +* chat example with new multiaddr ([#946](https://github.com/libp2p/js-libp2p/issues/946)) ([d8ba284](https://github.com/libp2p/js-libp2p/commit/d8ba2848833d9fb8a963d1b7c8d27062c6f829da)) +* dialer leaking resources after stopping ([#947](https://github.com/libp2p/js-libp2p/issues/947)) ([b291bc0](https://github.com/libp2p/js-libp2p/commit/b291bc06ec13feeb6e010730edfad754a3b2dc1b)) + + + +## [0.31.6](https://github.com/libp2p/js-libp2p/compare/v0.31.5...v0.31.6) (2021-05-27) + + +### Features + +* keychain rotate passphrase ([#944](https://github.com/libp2p/js-libp2p/issues/944)) ([478963a](https://github.com/libp2p/js-libp2p/commit/478963ad2d195444494c0acc54cb3847a29e117c)) + + + +## [0.31.5](https://github.com/libp2p/js-libp2p/compare/v0.31.4...v0.31.5) (2021-05-12) + + +### Bug Fixes + +* store remote agent and protocol version during identify ([#943](https://github.com/libp2p/js-libp2p/issues/943)) ([818d2b2](https://github.com/libp2p/js-libp2p/commit/818d2b2a98736f4242694479089396f6070cdad5)) + + + +## [0.31.4](https://github.com/libp2p/js-libp2p/compare/v0.31.3...v0.31.4) (2021-05-12) + + +### Bug Fixes + +* peerRouting.findPeer() trying to find self ([#941](https://github.com/libp2p/js-libp2p/issues/941)) ([a79c6b5](https://github.com/libp2p/js-libp2p/commit/a79c6b50d7fddbcdb1af53efae922cecad4c9a83)) + + + +## [0.31.3](https://github.com/libp2p/js-libp2p/compare/v0.31.2...v0.31.3) (2021-05-04) + + + +## [0.31.2](https://github.com/libp2p/js-libp2p/compare/v0.31.1...v0.31.2) (2021-04-30) + + +### Bug Fixes + +* moving averages record types ([#935](https://github.com/libp2p/js-libp2p/issues/935)) ([b5a9eb2](https://github.com/libp2p/js-libp2p/commit/b5a9eb208763efa027d0b4caae87c515b6f5869b)) + + + +## [0.31.1](https://github.com/libp2p/js-libp2p/compare/v0.31.0...v0.31.1) (2021-04-30) + + +### Bug Fixes + +* event emitter and interfaces types for discovery and routing ([#934](https://github.com/libp2p/js-libp2p/issues/934)) ([302bb90](https://github.com/libp2p/js-libp2p/commit/302bb9005891aa06b70a5f354bfac6b2d5a3c3b8)) + + + +# [0.31.0](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.7...v0.31.0) (2021-04-28) + + + +# [0.31.0-rc.7](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.6...v0.31.0-rc.7) (2021-04-27) + + +### Bug Fixes + +* address book guarantees no replicated entries are added ([#927](https://github.com/libp2p/js-libp2p/issues/927)) ([ac370fc](https://github.com/libp2p/js-libp2p/commit/ac370fc9679b51da8cee3791b6dd268d0695d136)) + + + +# [0.31.0-rc.6](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.5...v0.31.0-rc.6) (2021-04-22) + + +### Bug Fixes + +* keychain optional pw and use interfaces for validators and selectors instead ([#924](https://github.com/libp2p/js-libp2p/issues/924)) ([88b0415](https://github.com/libp2p/js-libp2p/commit/88b04156bf614650c2b14d49b12e969c5eecf04d)) + + + +# [0.31.0-rc.5](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.4...v0.31.0-rc.5) (2021-04-21) + + +### Bug Fixes + +* address book should not emit peer event if no addresses are known ([b4fb9b7](https://github.com/libp2p/js-libp2p/commit/b4fb9b7bf266ba03c4462c0a41b1c2691e4e88d4)) +* demand pubsub subclass instead of pubsub instance ([#922](https://github.com/libp2p/js-libp2p/issues/922)) ([086b0ec](https://github.com/libp2p/js-libp2p/commit/086b0ec0df2fac93845d0a0a6b2e2464e869afcd)) +* dht configuration selectors and validators ([#919](https://github.com/libp2p/js-libp2p/issues/919)) ([cc1f4af](https://github.com/libp2p/js-libp2p/commit/cc1f4af879a58e94538591851d0085ff98cd2641)) + + + +# [0.31.0-rc.4](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.3...v0.31.0-rc.4) (2021-04-20) + + +### Bug Fixes + +* add clientMode dht arg and upgrade interface-datastore ([#918](https://github.com/libp2p/js-libp2p/issues/918)) ([975e779](https://github.com/libp2p/js-libp2p/commit/975e77991e67dd9bff790b83df7bd6fa5ddcfc67)) +* do not add abort signals to useless addresses ([#913](https://github.com/libp2p/js-libp2p/issues/913)) ([06e8f3d](https://github.com/libp2p/js-libp2p/commit/06e8f3dd42432e4b37ab7904b02abde7d1cadda3)) +* specify pbjs root ([#917](https://github.com/libp2p/js-libp2p/issues/917)) ([b043bca](https://github.com/libp2p/js-libp2p/commit/b043bca607565cf534771e6cf975288a8ff3030b)) + + + +# [0.31.0-rc.3](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.2...v0.31.0-rc.3) (2021-04-19) + + +### Bug Fixes + +* remove inline arg types from function definitions ([#916](https://github.com/libp2p/js-libp2p/issues/916)) ([2af692f](https://github.com/libp2p/js-libp2p/commit/2af692fb4de572168524ae684608fc6526de4ef7)) + + + +# [0.31.0-rc.2](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.1...v0.31.0-rc.2) (2021-04-16) + + +### Bug Fixes + +* metrics stats and moving averages types ([#915](https://github.com/libp2p/js-libp2p/issues/915)) ([3d0a79e](https://github.com/libp2p/js-libp2p/commit/3d0a79eff3bc34a5bdc8ffa31e9b09345a02ad9d)) + + + +# [0.31.0-rc.1](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.0...v0.31.0-rc.1) (2021-04-16) + + +### Bug Fixes + +* dial protocol should throw if no protocol is provided ([#914](https://github.com/libp2p/js-libp2p/issues/914)) ([21c9aee](https://github.com/libp2p/js-libp2p/commit/21c9aeecb13440238aa6b0fb5a6731d2f87d4938)) + + +### BREAKING CHANGES + +* dialProtocol does not return connection when no protocols are provided + + + +# [0.31.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.30.12...v0.31.0-rc.0) (2021-04-15) + + + +## [0.30.12](https://github.com/libp2p/js-libp2p/compare/v0.30.11...v0.30.12) (2021-03-27) + + +### Bug Fixes + +* the API of es6-promisify is not the same as promisify-es6 ([#905](https://github.com/libp2p/js-libp2p/issues/905)) ([a7128f0](https://github.com/libp2p/js-libp2p/commit/a7128f07ec8d4b729145ecfc6ad1d585ffddea46)) + + + +## [0.30.11](https://github.com/libp2p/js-libp2p/compare/v0.30.10...v0.30.11) (2021-03-23) + + +### Bug Fixes + +* connection direction should be only inbound or outbound ([9504f19](https://github.com/libp2p/js-libp2p/commit/9504f1951a3cca55bb7b4e25e4934e4024034ee8)) +* interface-datastore update ([f5c1cd1](https://github.com/libp2p/js-libp2p/commit/f5c1cd1fb07bc73cf9d9da3c2eb4327bed4279a4)) + + + +## [0.30.10](https://github.com/libp2p/js-libp2p/compare/v0.30.9...v0.30.10) (2021-03-09) + + +### Bug Fixes + +* conn mgr access to moving averages record object ([#897](https://github.com/libp2p/js-libp2p/issues/897)) ([5f702f3](https://github.com/libp2p/js-libp2p/commit/5f702f3481afd4ad4fbc89f0e9b75a6d56b03520)) + + + +## [0.30.9](https://github.com/libp2p/js-libp2p/compare/v0.30.8...v0.30.9) (2021-02-25) + + +### Bug Fixes + +* transport manager fault tolerance should include tolerance to transport listen fail ([#893](https://github.com/libp2p/js-libp2p/issues/893)) ([3f314d5](https://github.com/libp2p/js-libp2p/commit/3f314d5e90f74583b721386d0c9c5d8363cd4de7)) + + + +## [0.30.8](https://github.com/libp2p/js-libp2p/compare/v0.30.7...v0.30.8) (2021-02-11) + + +### Bug Fixes + +* routers should only use dht if enabled ([#885](https://github.com/libp2p/js-libp2p/issues/885)) ([a34d2bb](https://github.com/libp2p/js-libp2p/commit/a34d2bbcc3d69ec3006137a909a7e8c53b9d378e)) + + + +## [0.30.7](https://github.com/libp2p/js-libp2p/compare/v0.30.6...v0.30.7) (2021-02-01) + + +### Bug Fixes + +* do not add observed address received from peers ([#882](https://github.com/libp2p/js-libp2p/issues/882)) ([a36b211](https://github.com/libp2p/js-libp2p/commit/a36b2112aafcee309a02de0cff5440cf69cd53a7)) + + + +## [0.30.6](https://github.com/libp2p/js-libp2p/compare/v0.30.5...v0.30.6) (2021-01-29) + + +### Bug Fixes + +* peer discovery type in config ([#878](https://github.com/libp2p/js-libp2p/issues/878)) ([3e7594f](https://github.com/libp2p/js-libp2p/commit/3e7594f69733bf374b374a6065458fa6cae81c5f)) +* unref nat manager retries ([#877](https://github.com/libp2p/js-libp2p/issues/877)) ([ce2a624](https://github.com/libp2p/js-libp2p/commit/ce2a624a09b3107c0b2b4752e666804ecea54fb5)) + + + +## [0.30.5](https://github.com/libp2p/js-libp2p/compare/v0.30.4...v0.30.5) (2021-01-28) + + +### Bug Fixes + +* create has optional peer id type ([#875](https://github.com/libp2p/js-libp2p/issues/875)) ([eeda056](https://github.com/libp2p/js-libp2p/commit/eeda05688330c17b810bf47544ef977386623317)) + + + +## [0.30.4](https://github.com/libp2p/js-libp2p/compare/v0.30.3...v0.30.4) (2021-01-27) + + +### Features + +* add UPnP NAT manager ([#810](https://github.com/libp2p/js-libp2p/issues/810)) ([0a6bc0d](https://github.com/libp2p/js-libp2p/commit/0a6bc0d1013dfd80ab600e8f74c1544b433ece29)) + + + +## [0.30.3](https://github.com/libp2p/js-libp2p/compare/v0.30.2...v0.30.3) (2021-01-27) + + + +## [0.30.2](https://github.com/libp2p/js-libp2p/compare/v0.30.1...v0.30.2) (2021-01-21) + + +### Bug Fixes + +* store multiaddrs during content and peer routing queries ([#865](https://github.com/libp2p/js-libp2p/issues/865)) ([45c3367](https://github.com/libp2p/js-libp2p/commit/45c33675a7412c66d0fd4e113ef8506077b6f492)) + + + +## [0.30.1](https://github.com/libp2p/js-libp2p/compare/v0.30.0...v0.30.1) (2021-01-18) + + +### Bug Fixes + +* event emitter types with local types ([#864](https://github.com/libp2p/js-libp2p/issues/864)) ([6c41e30](https://github.com/libp2p/js-libp2p/commit/6c41e3045608bcae8061d20501be5751dad8157a)) + + + +# [0.30.0](https://github.com/libp2p/js-libp2p/compare/v0.29.4...v0.30.0) (2020-12-16) + + +### Bug Fixes + +* remove test/dialing/utils extra file ([689c35e](https://github.com/libp2p/js-libp2p/commit/689c35ed1c68e514293a9895d496e2e8440454e9)) +* types from ipfs integration ([#832](https://github.com/libp2p/js-libp2p/issues/832)) ([9ae1b75](https://github.com/libp2p/js-libp2p/commit/9ae1b758e99e3fc9067e26b4eae4c15ccb1ba303)) + + +### chore + +* update pubsub ([#801](https://github.com/libp2p/js-libp2p/issues/801)) ([e50c6ab](https://github.com/libp2p/js-libp2p/commit/e50c6abcf2ebc80ebf2dfadd015ab21a20cffadc)) + + +### Features + +* auto relay ([#723](https://github.com/libp2p/js-libp2p/issues/723)) ([caf66ea](https://github.com/libp2p/js-libp2p/commit/caf66ea1439f6b75a0c321a16bd5c5d7d6a2bd47)) +* auto relay network query for new relays ([0bf0b7c](https://github.com/libp2p/js-libp2p/commit/0bf0b7cf8968d55002ac4c559ffb59985feeb092)) +* custom announce filter ([ef9d3ca](https://github.com/libp2p/js-libp2p/commit/ef9d3ca2c6f35d692d6079e74088c5146d46eebe)) +* custom dialer addr sorter ([#792](https://github.com/libp2p/js-libp2p/issues/792)) ([585ad52](https://github.com/libp2p/js-libp2p/commit/585ad52b4c71dd7514e99a287e0318b2b837ec48)) +* discover and connect to closest peers ([#798](https://github.com/libp2p/js-libp2p/issues/798)) ([baedf3f](https://github.com/libp2p/js-libp2p/commit/baedf3fe5ab946e938db1415d1662452cdfc0cc1)) + + +### BREAKING CHANGES + +* pubsub signing policy properties were changed according to libp2p-interfaces changes to a single property. The emitSelf option default value was also modified to match the routers value + + + +# [0.30.0-rc.2](https://github.com/libp2p/js-libp2p/compare/v0.30.0-rc.1...v0.30.0-rc.2) (2020-12-15) + + + +# [0.30.0-rc.1](https://github.com/libp2p/js-libp2p/compare/v0.30.0-rc.0...v0.30.0-rc.1) (2020-12-11) + + +### Bug Fixes + +* types from ipfs integration ([#832](https://github.com/libp2p/js-libp2p/issues/832)) ([216eb97](https://github.com/libp2p/js-libp2p/commit/216eb9730ef473f73a974c3dbaf306ecdc815c8b)) + + + +# [0.30.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.29.4...v0.30.0-rc.0) (2020-12-10) + + +### Bug Fixes + +* remove test/dialing/utils extra file ([3f1dc20](https://github.com/libp2p/js-libp2p/commit/3f1dc20caf1c80078f403deb9174cd06d08567ab)) + + +### chore + +* update pubsub ([#801](https://github.com/libp2p/js-libp2p/issues/801)) ([9205fce](https://github.com/libp2p/js-libp2p/commit/9205fce34d0cd8dd5d32988be34c110fc0a5b6e2)) + + +### Features + +* auto relay ([#723](https://github.com/libp2p/js-libp2p/issues/723)) ([65ec267](https://github.com/libp2p/js-libp2p/commit/65ec267e7f4826caacd042213c3fbacce589ab5b)) +* auto relay network query for new relays ([9faf1bf](https://github.com/libp2p/js-libp2p/commit/9faf1bfcf61581acc715b9be78b71dc14501835a)) +* custom announce filter ([48476d5](https://github.com/libp2p/js-libp2p/commit/48476d504a98b7b51b3e2dc64eab93670fde0c7b)) +* custom dialer addr sorter ([#792](https://github.com/libp2p/js-libp2p/issues/792)) ([91b15b6](https://github.com/libp2p/js-libp2p/commit/91b15b6790952b4db11264961d9c6f2a96d1fe43)) +* discover and connect to closest peers ([#798](https://github.com/libp2p/js-libp2p/issues/798)) ([b73106e](https://github.com/libp2p/js-libp2p/commit/b73106eba2d559621f427f7aa788e9b0ef47d135)) + + +### BREAKING CHANGES + +* pubsub signing policy properties were changed according to libp2p-interfaces changes to a single property. The emitSelf option default value was also modified to match the routers value + + + + +## [0.29.4](https://github.com/libp2p/js-libp2p/compare/v0.29.3...v0.29.4) (2020-12-09) + + +### Bug Fixes + +* dial self ([#826](https://github.com/libp2p/js-libp2p/issues/826)) ([6350a18](https://github.com/libp2p/js-libp2p/commit/6350a18)) + + +### Features + +* custom and store self agent version + store self protocol version ([#800](https://github.com/libp2p/js-libp2p/issues/800)) ([d0a9fad](https://github.com/libp2p/js-libp2p/commit/d0a9fad)) +* support custom listener options ([#822](https://github.com/libp2p/js-libp2p/issues/822)) ([8691465](https://github.com/libp2p/js-libp2p/commit/8691465)) + + + + +## [0.29.3](https://github.com/libp2p/js-libp2p/compare/v0.29.2...v0.29.3) (2020-11-04) + + +### Features + +* resolve multiaddrs before dial ([#782](https://github.com/libp2p/js-libp2p/issues/782)) ([093c0ea](https://github.com/libp2p/js-libp2p/commit/093c0ea)) + + + + +## [0.29.2](https://github.com/libp2p/js-libp2p/compare/v0.29.1...v0.29.2) (2020-10-23) + + +### Bug Fixes + +* cleanup open streams on conn close ([#791](https://github.com/libp2p/js-libp2p/issues/791)) ([06f26e5](https://github.com/libp2p/js-libp2p/commit/06f26e5)) + + + + +## [0.29.1](https://github.com/libp2p/js-libp2p/compare/v0.29.0...v0.29.1) (2020-10-22) + + +### Bug Fixes + +* catch error in upgrader close call ([e04224a](https://github.com/libp2p/js-libp2p/commit/e04224a)) +* ensure streams are closed on connection close ([4c6be91](https://github.com/libp2p/js-libp2p/commit/4c6be91)) +* flakey identify test firefox ([#774](https://github.com/libp2p/js-libp2p/issues/774)) ([60d437f](https://github.com/libp2p/js-libp2p/commit/60d437f)) + + + + +# [0.29.0](https://github.com/libp2p/js-libp2p/compare/v0.28.10...v0.29.0) (2020-08-27) + + +### Bug Fixes + +* do not return self on peerstore.peers ([15613cc](https://github.com/libp2p/js-libp2p/commit/15613cc)) +* peer record interop with go ([#739](https://github.com/libp2p/js-libp2p/issues/739)) ([93dda74](https://github.com/libp2p/js-libp2p/commit/93dda74)) +* replace node buffers with uint8arrays ([#730](https://github.com/libp2p/js-libp2p/issues/730)) ([1e86971](https://github.com/libp2p/js-libp2p/commit/1e86971)) +* revert new identify protocol versions ([3158366](https://github.com/libp2p/js-libp2p/commit/3158366)) +* signature compliant with spec ([4ab125e](https://github.com/libp2p/js-libp2p/commit/4ab125e)) + + +### Chores + +* update travis to use node lts and stable ([098f3d1](https://github.com/libp2p/js-libp2p/commit/098f3d1)) + + +### Features + +* cerified addressbook ([8f2e690](https://github.com/libp2p/js-libp2p/commit/8f2e690)) +* create self peer record in identify ([8a97dde](https://github.com/libp2p/js-libp2p/commit/8a97dde)) +* exchange signed peer records in identify ([e50f0ee](https://github.com/libp2p/js-libp2p/commit/e50f0ee)) +* gossipsub 1.1 ([#733](https://github.com/libp2p/js-libp2p/issues/733)) ([55c9bfa](https://github.com/libp2p/js-libp2p/commit/55c9bfa)) +* signed peer records record manager ([3e5d450](https://github.com/libp2p/js-libp2p/commit/3e5d450)) + + +### Reverts + +* reapply "fix: throw if no conn encryption module provided ([#665](https://github.com/libp2p/js-libp2p/issues/665))" ([689f90a](https://github.com/libp2p/js-libp2p/commit/689f90a)) + + +### BREAKING CHANGES + +* pubsub implementation is now directly exposed and its API was updated according to the new pubsub interface in js-libp2p-interfaces repo + +* chore: use gossipsub branch with src added + +* fix: add pubsub handlers adapter + +* chore: fix deps + +* chore: update pubsub docs and examples + +* chore: apply suggestions from code review + +Co-authored-by: Jacob Heun + +* chore: use new floodsub + +* chore: change validator doc set + +Co-authored-by: Jacob Heun + +* chore: add new gossipsub src + +Co-authored-by: Jacob Heun +* - All deps used by this module now use Uint8Arrays in place of node Buffers + +* chore: browser fixes + +* chore: remove .only + +* chore: stringify uint8array before parsing + +* chore: update interop suite + +* chore: remove ts from build command + +* chore: update deps + +* fix: update records to use uint8array + +* chore: fix lint + +* chore: update deps + +Co-authored-by: Jacob Heun +* this drops testing support in node 10. + + + + +# [0.29.0-rc.1](https://github.com/libp2p/js-libp2p/compare/v0.29.0-rc.0...v0.29.0-rc.1) (2020-08-27) + + +### Bug Fixes + +* peer record interop with go ([#739](https://github.com/libp2p/js-libp2p/issues/739)) ([c4c7ef9](https://github.com/libp2p/js-libp2p/commit/c4c7ef9)) + + + + +# [0.29.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.28.10...v0.29.0-rc.0) (2020-08-25) + + +### Bug Fixes + +* do not return self on peerstore.peers ([e1b8edc](https://github.com/libp2p/js-libp2p/commit/e1b8edc)) +* replace node buffers with uint8arrays ([#730](https://github.com/libp2p/js-libp2p/issues/730)) ([507f8c4](https://github.com/libp2p/js-libp2p/commit/507f8c4)) +* revert new identify protocol versions ([a798c65](https://github.com/libp2p/js-libp2p/commit/a798c65)) +* signature compliant with spec ([97b5d2a](https://github.com/libp2p/js-libp2p/commit/97b5d2a)) + + +### Chores + +* update travis to use node lts and stable ([c272288](https://github.com/libp2p/js-libp2p/commit/c272288)) + + +### Features + +* cerified addressbook ([e0ed258](https://github.com/libp2p/js-libp2p/commit/e0ed258)) +* create self peer record in identify ([83922a7](https://github.com/libp2p/js-libp2p/commit/83922a7)) +* exchange signed peer records in identify ([f835457](https://github.com/libp2p/js-libp2p/commit/f835457)) +* gossipsub 1.1 ([#733](https://github.com/libp2p/js-libp2p/issues/733)) ([e14ce40](https://github.com/libp2p/js-libp2p/commit/e14ce40)) +* signed peer records record manager ([f95edf1](https://github.com/libp2p/js-libp2p/commit/f95edf1)) + + +### Reverts + +* reapply "fix: throw if no conn encryption module provided ([#665](https://github.com/libp2p/js-libp2p/issues/665))" ([ad7f02e](https://github.com/libp2p/js-libp2p/commit/ad7f02e)) + + +### BREAKING CHANGES + +* pubsub implementation is now directly exposed and its API was updated according to the new pubsub interface in js-libp2p-interfaces repo + +* chore: use gossipsub branch with src added + +* fix: add pubsub handlers adapter + +* chore: fix deps + +* chore: update pubsub docs and examples + +* chore: apply suggestions from code review + +Co-authored-by: Jacob Heun + +* chore: use new floodsub + +* chore: change validator doc set + +Co-authored-by: Jacob Heun + +* chore: add new gossipsub src + +Co-authored-by: Jacob Heun +* - All deps used by this module now use Uint8Arrays in place of node Buffers + +* chore: browser fixes + +* chore: remove .only + +* chore: stringify uint8array before parsing + +* chore: update interop suite + +* chore: remove ts from build command + +* chore: update deps + +* fix: update records to use uint8array + +* chore: fix lint + +* chore: update deps + +Co-authored-by: Jacob Heun +* this drops testing support in node 10. + + + + +## [0.28.10](https://github.com/libp2p/js-libp2p/compare/v0.28.9...v0.28.10) (2020-08-05) + + +### Bug Fixes + +* allow certain keychain operations without a password ([#726](https://github.com/libp2p/js-libp2p/issues/726)) ([8c56ec0](https://github.com/libp2p/js-libp2p/commit/8c56ec0)) +* **identify:** make agentversion dynamic and add it to the peerstore ([#724](https://github.com/libp2p/js-libp2p/issues/724)) ([726a746](https://github.com/libp2p/js-libp2p/commit/726a746)) + + +### Features + +* **keychain:** add support for ed25519 and secp keys ([#725](https://github.com/libp2p/js-libp2p/issues/725)) ([51d7ca4](https://github.com/libp2p/js-libp2p/commit/51d7ca4)) + + + + +## [0.28.9](https://github.com/libp2p/js-libp2p/compare/v0.28.8...v0.28.9) (2020-07-27) + + +### Bug Fixes + +* ping multiaddr from peer not previously stored in peerstore ([#719](https://github.com/libp2p/js-libp2p/issues/719)) ([2440c87](https://github.com/libp2p/js-libp2p/commit/2440c87)) + + + + +## [0.28.8](https://github.com/libp2p/js-libp2p/compare/v0.28.7...v0.28.8) (2020-07-20) + + +### Bug Fixes + +* create dial target for peer with no known addrs ([#715](https://github.com/libp2p/js-libp2p/issues/715)) ([7da9ad4](https://github.com/libp2p/js-libp2p/commit/7da9ad4)) + + + + +## [0.28.7](https://github.com/libp2p/js-libp2p/compare/v0.28.6...v0.28.7) (2020-07-14) + + +### Bug Fixes + +* retimer reschedule does not work as interval ([#710](https://github.com/libp2p/js-libp2p/issues/710)) ([999c1b7](https://github.com/libp2p/js-libp2p/commit/999c1b7)) + + + + +## [0.28.6](https://github.com/libp2p/js-libp2p/compare/v0.28.5...v0.28.6) (2020-07-14) + + +### Bug Fixes + +* not dial all known peers in parallel on startup ([#698](https://github.com/libp2p/js-libp2p/issues/698)) ([9ccab40](https://github.com/libp2p/js-libp2p/commit/9ccab40)) + + + + +## [0.28.5](https://github.com/libp2p/js-libp2p/compare/v0.28.4...v0.28.5) (2020-07-10) + + +### Bug Fixes + +* pass libp2p to the dht ([#700](https://github.com/libp2p/js-libp2p/issues/700)) ([5a84dd5](https://github.com/libp2p/js-libp2p/commit/5a84dd5)) + + + + +## [0.28.4](https://github.com/libp2p/js-libp2p/compare/v0.28.3...v0.28.4) (2020-07-03) + + + + +## [0.28.3](https://github.com/libp2p/js-libp2p/compare/v0.28.2...v0.28.3) (2020-06-18) + + +### Bug Fixes + +* catch pipe errors ([#678](https://github.com/libp2p/js-libp2p/issues/678)) ([a8219e6](https://github.com/libp2p/js-libp2p/commit/a8219e6)) + + + + +## [0.28.2](https://github.com/libp2p/js-libp2p/compare/v0.28.1...v0.28.2) (2020-06-15) + + +### Reverts + +* "fix: throw if no conn encryption module provided ([#665](https://github.com/libp2p/js-libp2p/issues/665))" ([b621fbd](https://github.com/libp2p/js-libp2p/commit/b621fbd)) + + + + +## [0.28.1](https://github.com/libp2p/js-libp2p/compare/v0.28.0...v0.28.1) (2020-06-12) + + +### Bug Fixes + +* throw if no conn encryption module provided ([#665](https://github.com/libp2p/js-libp2p/issues/665)) ([c038550](https://github.com/libp2p/js-libp2p/commit/c038550)) + + +### Features + +* add ConnectionManager#getAll ([8f680e2](https://github.com/libp2p/js-libp2p/commit/8f680e2)) + + + + +# [0.28.0](https://github.com/libp2p/js-libp2p/compare/v0.28.0-rc.0...v0.28.0) (2020-06-05) + + + + +# [0.28.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.27.8...v0.28.0-rc.0) (2020-05-28) + + +### Bug Fixes + +* always emit when a connection is made ([72f37ac](https://github.com/libp2p/js-libp2p/commit/72f37ac)) +* expose the muxed stream interface on inbound streams ([52a615f](https://github.com/libp2p/js-libp2p/commit/52a615f)) +* libp2p connections getter ([aaf62a4](https://github.com/libp2p/js-libp2p/commit/aaf62a4)) +* onConnect should not add addr to the addressBook ([2b45fee](https://github.com/libp2p/js-libp2p/commit/2b45fee)) +* use libp2p.multiaddrs instead of listen ([7fbd155](https://github.com/libp2p/js-libp2p/commit/7fbd155)) +* **example:** rename misleading variable ([#645](https://github.com/libp2p/js-libp2p/issues/645)) ([b781911](https://github.com/libp2p/js-libp2p/commit/b781911)) + + +### Chores + +* deprecate old peer store api ([#598](https://github.com/libp2p/js-libp2p/issues/598)) ([ed6d5bb](https://github.com/libp2p/js-libp2p/commit/ed6d5bb)) +* remove peer-info usage ([12e48ad](https://github.com/libp2p/js-libp2p/commit/12e48ad)) + + +### Features + +* address and proto books ([#590](https://github.com/libp2p/js-libp2p/issues/590)) ([e9d225c](https://github.com/libp2p/js-libp2p/commit/e9d225c)) +* address manager ([2a7967c](https://github.com/libp2p/js-libp2p/commit/2a7967c)) +* keybook ([ce38033](https://github.com/libp2p/js-libp2p/commit/ce38033)) +* metadata book ([#638](https://github.com/libp2p/js-libp2p/issues/638)) ([84b935f](https://github.com/libp2p/js-libp2p/commit/84b935f)) +* peerStore persistence ([5123a83](https://github.com/libp2p/js-libp2p/commit/5123a83)) +* support dial only on transport manager to tolerate errors ([#643](https://github.com/libp2p/js-libp2p/issues/643)) ([698c1df](https://github.com/libp2p/js-libp2p/commit/698c1df)) + + +### BREAKING CHANGES + +* all API methods with peer-info parameters or return values were changed. You can check the API.md document, in order to check the new values to use +* the peer-store api changed. Check the API docs for the new specification. + +* chore: apply suggestions from code review + +Co-Authored-By: Jacob Heun + +* chore: apply suggestions from code review + +Co-Authored-By: Jacob Heun + +Co-authored-by: Jacob Heun + + + + +## [0.27.8](https://github.com/libp2p/js-libp2p/compare/v0.27.7...v0.27.8) (2020-05-06) + + +### Bug Fixes + +* reset discovery services upon stop ([#618](https://github.com/libp2p/js-libp2p/issues/618)) ([ea0621b](https://github.com/libp2p/js-libp2p/commit/ea0621b)) + + + + +## [0.27.7](https://github.com/libp2p/js-libp2p/compare/v0.27.6...v0.27.7) (2020-04-24) + + +### Bug Fixes + +* remove node global ([#587](https://github.com/libp2p/js-libp2p/issues/587)) ([9b13fe3](https://github.com/libp2p/js-libp2p/commit/9b13fe3)) + + + + +## [0.27.6](https://github.com/libp2p/js-libp2p/compare/v0.27.5...v0.27.6) (2020-04-16) + + +### Bug Fixes + +* add null check in libp2p.hangUp() ([c940f2d](https://github.com/libp2p/js-libp2p/commit/c940f2d)) +* make circuit relay listening addresses more forgiving ([#604](https://github.com/libp2p/js-libp2p/issues/604)) ([e192eb6](https://github.com/libp2p/js-libp2p/commit/e192eb6)) + + + + +## [0.27.5](https://github.com/libp2p/js-libp2p/compare/v0.27.4...v0.27.5) (2020-04-06) + + +### Bug Fixes + +* await peer discovery start in libp2p start ([#600](https://github.com/libp2p/js-libp2p/issues/600)) ([bd7fd0f](https://github.com/libp2p/js-libp2p/commit/bd7fd0f)) + + + + +## [0.27.4](https://github.com/libp2p/js-libp2p/compare/v0.27.3...v0.27.4) (2020-03-31) + + +### Bug Fixes + +* only use a single export ([#596](https://github.com/libp2p/js-libp2p/issues/596)) ([3072875](https://github.com/libp2p/js-libp2p/commit/3072875)) +* pass libp2p to discovery services ([#597](https://github.com/libp2p/js-libp2p/issues/597)) ([9e35fbc](https://github.com/libp2p/js-libp2p/commit/9e35fbc)) +* **test:** improve flakey random walk discovery test ([#574](https://github.com/libp2p/js-libp2p/issues/574)) ([f4ec355](https://github.com/libp2p/js-libp2p/commit/f4ec355)) +* remove use of assert module ([#561](https://github.com/libp2p/js-libp2p/issues/561)) ([a8984c6](https://github.com/libp2p/js-libp2p/commit/a8984c6)) + + + + +## [0.27.3](https://github.com/libp2p/js-libp2p/compare/v0.27.2...v0.27.3) (2020-02-11) + + +### Bug Fixes + +* dont allow multiaddr dials without a peer id ([#558](https://github.com/libp2p/js-libp2p/issues/558)) ([a317a8b](https://github.com/libp2p/js-libp2p/commit/a317a8b)) + + + + +## [0.27.2](https://github.com/libp2p/js-libp2p/compare/v0.27.1...v0.27.2) (2020-02-05) + + +### Bug Fixes + +* ensure identify streams are closed ([#551](https://github.com/libp2p/js-libp2p/issues/551)) ([f662fdc](https://github.com/libp2p/js-libp2p/commit/f662fdc)) + + + + +## [0.27.1](https://github.com/libp2p/js-libp2p/compare/v0.27.0...v0.27.1) (2020-02-03) + + +### Bug Fixes + +* stop stream after first pong received ([#545](https://github.com/libp2p/js-libp2p/issues/545)) ([be8fc9d](https://github.com/libp2p/js-libp2p/commit/be8fc9d)) + + + + +# [0.27.0](https://github.com/libp2p/js-libp2p/compare/v0.26.2...v0.27.0) (2020-01-28) + + +### Bug Fixes + +* clean up peer discovery flow ([#494](https://github.com/libp2p/js-libp2p/issues/494)) ([12fc069](https://github.com/libp2p/js-libp2p/commit/12fc069)) +* clean up pending dials abort per feedback ([633b0c2](https://github.com/libp2p/js-libp2p/commit/633b0c2)) +* conn mngr min/max connection values ([#528](https://github.com/libp2p/js-libp2p/issues/528)) ([ba4681b](https://github.com/libp2p/js-libp2p/commit/ba4681b)) +* correct release readme ([ce8e60b](https://github.com/libp2p/js-libp2p/commit/ce8e60b)) +* examples readme typos ([#481](https://github.com/libp2p/js-libp2p/issues/481)) ([35ac02d](https://github.com/libp2p/js-libp2p/commit/35ac02d)) +* make dialer configurable ([#521](https://github.com/libp2p/js-libp2p/issues/521)) ([4ca481b](https://github.com/libp2p/js-libp2p/commit/4ca481b)) +* performance bottleneck in stat.js ([#463](https://github.com/libp2p/js-libp2p/issues/463)) ([93a1e42](https://github.com/libp2p/js-libp2p/commit/93a1e42)) +* registrar should filter the disconnected conn ([#532](https://github.com/libp2p/js-libp2p/issues/532)) ([bb2e56e](https://github.com/libp2p/js-libp2p/commit/bb2e56e)) +* release tokens as soon as they are available ([2570a1b](https://github.com/libp2p/js-libp2p/commit/2570a1b)) +* replace peerInfo addresses with listen addresses ([#485](https://github.com/libp2p/js-libp2p/issues/485)) ([1999606](https://github.com/libp2p/js-libp2p/commit/1999606)) +* stop discoveries ([#530](https://github.com/libp2p/js-libp2p/issues/530)) ([4222c49](https://github.com/libp2p/js-libp2p/commit/4222c49)) +* token release logic ([90ecc57](https://github.com/libp2p/js-libp2p/commit/90ecc57)) +* upgrader should not need muxers ([#517](https://github.com/libp2p/js-libp2p/issues/517)) ([5d7ee50](https://github.com/libp2p/js-libp2p/commit/5d7ee50)) +* use toB58String everywhere to be consistent ([#537](https://github.com/libp2p/js-libp2p/issues/537)) ([c1038be](https://github.com/libp2p/js-libp2p/commit/c1038be)) + + +### Features + +* abort all pending dials on stop ([ba02764](https://github.com/libp2p/js-libp2p/commit/ba02764)) +* add early token recycling in ([a5b54a7](https://github.com/libp2p/js-libp2p/commit/a5b54a7)) +* add libp2p.connections getter ([#522](https://github.com/libp2p/js-libp2p/issues/522)) ([6445fda](https://github.com/libp2p/js-libp2p/commit/6445fda)) +* add token based dialer ([e445a17](https://github.com/libp2p/js-libp2p/commit/e445a17)) +* allow transport options to be passed on creation ([#524](https://github.com/libp2p/js-libp2p/issues/524)) ([c339be1](https://github.com/libp2p/js-libp2p/commit/c339be1)) +* coalescing dial support ([#518](https://github.com/libp2p/js-libp2p/issues/518)) ([15f7c2a](https://github.com/libp2p/js-libp2p/commit/15f7c2a)) +* discovery modules ([#486](https://github.com/libp2p/js-libp2p/issues/486)) ([18a062e](https://github.com/libp2p/js-libp2p/commit/18a062e)) +* discovery modules from transports should be added ([#510](https://github.com/libp2p/js-libp2p/issues/510)) ([f1eb373](https://github.com/libp2p/js-libp2p/commit/f1eb373)) +* peer store ([#470](https://github.com/libp2p/js-libp2p/issues/470)) ([582094a](https://github.com/libp2p/js-libp2p/commit/582094a)) +* registrar ([#471](https://github.com/libp2p/js-libp2p/issues/471)) ([9d52b80](https://github.com/libp2p/js-libp2p/commit/9d52b80)) +* support peer-id instances in peer store operations ([#491](https://github.com/libp2p/js-libp2p/issues/491)) ([8da9fc9](https://github.com/libp2p/js-libp2p/commit/8da9fc9)) + + + + +# [0.27.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.2...v0.27.0-rc.0) (2020-01-24) + + +### Bug Fixes + +* registrar should filter the disconnected conn ([#532](https://github.com/libp2p/js-libp2p/issues/532)) ([83409de](https://github.com/libp2p/js-libp2p/commit/83409de)) +* stop discoveries ([#530](https://github.com/libp2p/js-libp2p/issues/530)) ([c44e6e3](https://github.com/libp2p/js-libp2p/commit/c44e6e3)) +* use toB58String everywhere to be consistent ([#537](https://github.com/libp2p/js-libp2p/issues/537)) ([31d1b23](https://github.com/libp2p/js-libp2p/commit/31d1b23)) + + + + +# [0.27.0-pre.2](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.1...v0.27.0-pre.2) (2020-01-07) + + +### Bug Fixes + +* conn mngr min/max connection values ([#528](https://github.com/libp2p/js-libp2p/issues/528)) ([a1717da](https://github.com/libp2p/js-libp2p/commit/a1717da)) +* make dialer configurable ([#521](https://github.com/libp2p/js-libp2p/issues/521)) ([24c3ce6](https://github.com/libp2p/js-libp2p/commit/24c3ce6)) +* upgrader should not need muxers ([#517](https://github.com/libp2p/js-libp2p/issues/517)) ([56a1825](https://github.com/libp2p/js-libp2p/commit/56a1825)) + + +### Features + +* add libp2p.connections getter ([#522](https://github.com/libp2p/js-libp2p/issues/522)) ([6ca19c5](https://github.com/libp2p/js-libp2p/commit/6ca19c5)) +* allow transport options to be passed on creation ([#524](https://github.com/libp2p/js-libp2p/issues/524)) ([0d4b2bd](https://github.com/libp2p/js-libp2p/commit/0d4b2bd)) + + + + +# [0.27.0-pre.1](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.0...v0.27.0-pre.1) (2019-12-15) + + +### Features + +* coalescing dial support ([#518](https://github.com/libp2p/js-libp2p/issues/518)) ([4a871bb](https://github.com/libp2p/js-libp2p/commit/4a871bb)) + + + + +# [0.27.0-pre.0](https://github.com/libp2p/js-libp2p/compare/v0.26.2...v0.27.0-pre.0) (2019-12-12) + + +### Bug Fixes + +* clean up peer discovery flow ([#494](https://github.com/libp2p/js-libp2p/issues/494)) ([f3eb1f1](https://github.com/libp2p/js-libp2p/commit/f3eb1f1)) +* clean up pending dials abort per feedback ([7c3371b](https://github.com/libp2p/js-libp2p/commit/7c3371b)) +* correct release readme ([c4bc00b](https://github.com/libp2p/js-libp2p/commit/c4bc00b)) +* examples readme typos ([#481](https://github.com/libp2p/js-libp2p/issues/481)) ([35ac02d](https://github.com/libp2p/js-libp2p/commit/35ac02d)) +* performance bottleneck in stat.js ([#463](https://github.com/libp2p/js-libp2p/issues/463)) ([93a1e42](https://github.com/libp2p/js-libp2p/commit/93a1e42)) +* release tokens as soon as they are available ([43440aa](https://github.com/libp2p/js-libp2p/commit/43440aa)) +* replace peerInfo addresses with listen addresses ([#485](https://github.com/libp2p/js-libp2p/issues/485)) ([acbbc0f](https://github.com/libp2p/js-libp2p/commit/acbbc0f)) +* token release logic ([1838a64](https://github.com/libp2p/js-libp2p/commit/1838a64)) + + +### Features + +* abort all pending dials on stop ([754fbc2](https://github.com/libp2p/js-libp2p/commit/754fbc2)) +* add early token recycling in ([24c6037](https://github.com/libp2p/js-libp2p/commit/24c6037)) +* add token based dialer ([f8540fa](https://github.com/libp2p/js-libp2p/commit/f8540fa)) +* discovery modules ([#486](https://github.com/libp2p/js-libp2p/issues/486)) ([997ee16](https://github.com/libp2p/js-libp2p/commit/997ee16)) +* discovery modules from transports should be added ([#510](https://github.com/libp2p/js-libp2p/issues/510)) ([af96dcc](https://github.com/libp2p/js-libp2p/commit/af96dcc)) +* peer store ([#470](https://github.com/libp2p/js-libp2p/issues/470)) ([f3e276e](https://github.com/libp2p/js-libp2p/commit/f3e276e)) +* registrar ([#471](https://github.com/libp2p/js-libp2p/issues/471)) ([797d8f0](https://github.com/libp2p/js-libp2p/commit/797d8f0)) +* support peer-id instances in peer store operations ([#491](https://github.com/libp2p/js-libp2p/issues/491)) ([11ed6bd](https://github.com/libp2p/js-libp2p/commit/11ed6bd)) + + + + +## [0.26.2](https://github.com/libp2p/js-libp2p/compare/v0.26.1...v0.26.2) (2019-09-24) + + +### Bug Fixes + +* pubsub promisify ([#456](https://github.com/libp2p/js-libp2p/issues/456)) ([ae6af20](https://github.com/libp2p/js-libp2p/commit/ae6af20)) + + + + +## [0.26.1](https://github.com/libp2p/js-libp2p/compare/v0.26.0...v0.26.1) (2019-08-21) + + +### Bug Fixes + +* avoid using superstruct interface ([aa95ab9](https://github.com/libp2p/js-libp2p/commit/aa95ab9)) +* improve config defaults ([#409](https://github.com/libp2p/js-libp2p/issues/409)) ([3eef695](https://github.com/libp2p/js-libp2p/commit/3eef695)), closes [#406](https://github.com/libp2p/js-libp2p/issues/406) +* pubsub configuration ([#404](https://github.com/libp2p/js-libp2p/issues/404)) ([b0f124b](https://github.com/libp2p/js-libp2p/commit/b0f124b)), closes [#401](https://github.com/libp2p/js-libp2p/issues/401) [#401](https://github.com/libp2p/js-libp2p/issues/401) [#401](https://github.com/libp2p/js-libp2p/issues/401) [#401](https://github.com/libp2p/js-libp2p/issues/401) [#401](https://github.com/libp2p/js-libp2p/issues/401) +* reference files directly to avoid npm install failures ([#408](https://github.com/libp2p/js-libp2p/issues/408)) ([b3deb35](https://github.com/libp2p/js-libp2p/commit/b3deb35)) +* reject rather than throw in get peer info ([#410](https://github.com/libp2p/js-libp2p/issues/410)) ([60b0cbc](https://github.com/libp2p/js-libp2p/commit/60b0cbc)), closes [#400](https://github.com/libp2p/js-libp2p/issues/400) + + + + +# [0.26.0](https://github.com/libp2p/js-libp2p/compare/v0.26.0-rc.3...v0.26.0) (2019-08-07) + + + + +# [0.26.0-rc.3](https://github.com/libp2p/js-libp2p/compare/v0.26.0-rc.2...v0.26.0-rc.3) (2019-08-06) + + +### Bug Fixes + +* promisified methods ([#398](https://github.com/libp2p/js-libp2p/issues/398)) ([ff7a6c8](https://github.com/libp2p/js-libp2p/commit/ff7a6c8)) + + + + +# [0.26.0-rc.2](https://github.com/libp2p/js-libp2p/compare/v0.26.0-rc.1...v0.26.0-rc.2) (2019-08-01) + + +### Bug Fixes + +* dont override methods of created instance ([#394](https://github.com/libp2p/js-libp2p/issues/394)) ([3e95e6f](https://github.com/libp2p/js-libp2p/commit/3e95e6f)) +* pubsub default config ([#393](https://github.com/libp2p/js-libp2p/issues/393)) ([f4f3f0f](https://github.com/libp2p/js-libp2p/commit/f4f3f0f)) + + +### Chores + +* update switch ([#395](https://github.com/libp2p/js-libp2p/issues/395)) ([684f283](https://github.com/libp2p/js-libp2p/commit/684f283)) + + +### BREAKING CHANGES + +* switch configuration has changed. +'blacklistTTL' is now 'denyTTL' and 'blackListAttempts' is now 'denyAttempts' + + + + +# [0.26.0-rc.1](https://github.com/libp2p/js-libp2p/compare/v0.26.0-rc.0...v0.26.0-rc.1) (2019-07-31) + + + + +# [0.26.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.25.5...v0.26.0-rc.0) (2019-07-31) + + +### Bug Fixes + +* make subscribe comply with ipfs interface ([#389](https://github.com/libp2p/js-libp2p/issues/389)) ([9554b05](https://github.com/libp2p/js-libp2p/commit/9554b05)) + + +### Features + +* integrate gossipsub by default ([#365](https://github.com/libp2p/js-libp2p/issues/365)) ([791f39a](https://github.com/libp2p/js-libp2p/commit/791f39a)) +* promisify all api methods that accept callbacks ([#381](https://github.com/libp2p/js-libp2p/issues/381)) ([df6ef45](https://github.com/libp2p/js-libp2p/commit/df6ef45)) + + +### BREAKING CHANGES + +* new configuration for deciding the implementation of pubsub to be used. +In this context, the experimental flags were also removed. See the README for the latest usage. +* The ipfs interface specified that options +should be provided after the handler, not before. +https://github.com/ipfs/interface-js-ipfs-core/blob/v0.109.0/SPEC/PUBSUB.md#pubsubsubscribe + +This corrects the order of parameters. See the jsdocs examples +for subscribe to see how it should be used. + + + + +## [0.25.5](https://github.com/libp2p/js-libp2p/compare/v0.25.4...v0.25.5) (2019-07-12) + + +### Bug Fixes + +* peer routing for delegate router ([#377](https://github.com/libp2p/js-libp2p/issues/377)) ([905c911](https://github.com/libp2p/js-libp2p/commit/905c911)), closes [/github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go#L15-L24](https://github.com//github.com/libp2p/go-libp2p-core/blob/6e566d10f4a5447317a66d64c7459954b969bdab/routing/query.go/issues/L15-L24) + + + + +## [0.25.4](https://github.com/libp2p/js-libp2p/compare/v0.25.3...v0.25.4) (2019-06-07) + + +### Features + +* add createLibp2p to generate a PeerInfo instance ([#367](https://github.com/libp2p/js-libp2p/issues/367)) ([04faf18](https://github.com/libp2p/js-libp2p/commit/04faf18)) +* pass libp2p as option to transport creation ([#363](https://github.com/libp2p/js-libp2p/issues/363)) ([b06ca1b](https://github.com/libp2p/js-libp2p/commit/b06ca1b)) + + + + +## [0.25.3](https://github.com/libp2p/js-libp2p/compare/v0.25.2...v0.25.3) (2019-05-07) + + +### Features + +* sign pubsub messages ([#362](https://github.com/libp2p/js-libp2p/issues/362)) ([40978a1](https://github.com/libp2p/js-libp2p/commit/40978a1)) + + + + +## [0.25.2](https://github.com/libp2p/js-libp2p/compare/v0.25.1...v0.25.2) (2019-04-17) + + +### Bug Fixes + +* dht config ([#359](https://github.com/libp2p/js-libp2p/issues/359)) ([f3801f0](https://github.com/libp2p/js-libp2p/commit/f3801f0)) + + + + +## [0.25.1](https://github.com/libp2p/js-libp2p/compare/v0.25.0...v0.25.1) (2019-04-16) + + +### Bug Fixes + +* bail when discovering self ([#357](https://github.com/libp2p/js-libp2p/issues/357)) ([f28dffb](https://github.com/libp2p/js-libp2p/commit/f28dffb)) + + + + +# [0.25.0](https://github.com/libp2p/js-libp2p/compare/v0.25.0-rc.6...v0.25.0) (2019-04-12) + + +### Bug Fixes + +* allow switch to be configured ([#354](https://github.com/libp2p/js-libp2p/issues/354)) ([eb5aa03](https://github.com/libp2p/js-libp2p/commit/eb5aa03)) + + + + +# [0.25.0-rc.6](https://github.com/libp2p/js-libp2p/compare/v0.25.0-rc.5...v0.25.0-rc.6) (2019-04-11) + + +### Bug Fixes + +* connection emits ([#352](https://github.com/libp2p/js-libp2p/issues/352)) ([313b1ea](https://github.com/libp2p/js-libp2p/commit/313b1ea)) +* remove unneeded peerbook puts ([#348](https://github.com/libp2p/js-libp2p/issues/348)) ([e5f19e8](https://github.com/libp2p/js-libp2p/commit/e5f19e8)) + + +### Features + +* auto dial discovered peers ([#349](https://github.com/libp2p/js-libp2p/issues/349)) ([01aa447](https://github.com/libp2p/js-libp2p/commit/01aa447)) + + + + +# [0.25.0-rc.5](https://github.com/libp2p/js-libp2p/compare/v0.25.0-rc.4...v0.25.0-rc.5) (2019-03-21) + + +### Bug Fixes + +* disable dht by default [#338](https://github.com/libp2p/js-libp2p/issues/338) ([#339](https://github.com/libp2p/js-libp2p/issues/339)) ([e52ce66](https://github.com/libp2p/js-libp2p/commit/e52ce66)) + + +### Features + +* update to the latest switch ([#336](https://github.com/libp2p/js-libp2p/issues/336)) ([eee60ed](https://github.com/libp2p/js-libp2p/commit/eee60ed)) + + + + +# [0.25.0-rc.4](https://github.com/libp2p/js-libp2p/compare/v0.25.0-rc.3...v0.25.0-rc.4) (2019-03-06) + + + + +# [0.25.0-rc.3](https://github.com/libp2p/js-libp2p/compare/v0.25.0-rc.2...v0.25.0-rc.3) (2019-02-26) + + + + +# [0.25.0-rc.2](https://github.com/libp2p/js-libp2p/compare/v0.25.0-rc.1...v0.25.0-rc.2) (2019-02-26) + + +### Bug Fixes + +* make the config less restrictive ([#329](https://github.com/libp2p/js-libp2p/issues/329)) ([5f92acd](https://github.com/libp2p/js-libp2p/commit/5f92acd)) + + + + +# [0.25.0-rc.1](https://github.com/libp2p/js-libp2p/compare/v0.25.0-rc.0...v0.25.0-rc.1) (2019-02-21) + + +### Bug Fixes + +* bundle-size ([#298](https://github.com/libp2p/js-libp2p/issues/298)) ([d497961](https://github.com/libp2p/js-libp2p/commit/d497961)) +* emit peer discovery for dht discovery ([9e7a080](https://github.com/libp2p/js-libp2p/commit/9e7a080)) + + +### Features + +* support unsubscribe all for pubsub ([#321](https://github.com/libp2p/js-libp2p/issues/321)) ([6e76aad](https://github.com/libp2p/js-libp2p/commit/6e76aad)) + + + + +## [0.24.4](https://github.com/libp2p/js-libp2p/compare/v0.24.3...v0.24.4) (2019-01-04) + + + + +## [0.24.3](https://github.com/libp2p/js-libp2p/compare/v0.24.2...v0.24.3) (2018-12-14) + + +### Bug Fixes + +* not started yet ([#297](https://github.com/libp2p/js-libp2p/issues/297)) ([fdfb7b4](https://github.com/libp2p/js-libp2p/commit/fdfb7b4)) + + + + +## [0.24.2](https://github.com/libp2p/js-libp2p/compare/v0.24.1...v0.24.2) (2018-12-04) + + +### Bug Fixes + +* use symbol instead of constructor name ([#292](https://github.com/libp2p/js-libp2p/issues/292)) ([53ed3bd](https://github.com/libp2p/js-libp2p/commit/53ed3bd)) + + + + +## [0.24.1](https://github.com/libp2p/js-libp2p/compare/v0.24.0...v0.24.1) (2018-12-03) + + +### Features + +* allow configurable validators and selectors to the dht ([#288](https://github.com/libp2p/js-libp2p/issues/288)) ([7d12eb9](https://github.com/libp2p/js-libp2p/commit/7d12eb9)) + + + + +# [0.24.0](https://github.com/libp2p/js-libp2p/compare/v0.24.0-rc.3...v0.24.0) (2018-11-16) + +### Bug Fixes + +* add maxtimeout to dht get ([#248](https://github.com/libp2p/js-libp2p/issues/248)) ([69f7264](https://github.com/libp2p/js-libp2p/commit/69f7264)) +* dht get options ([4460e82](https://github.com/libp2p/js-libp2p/commit/4460e82)) +* dont call callback before it's properly set ([17b5f73](https://github.com/libp2p/js-libp2p/commit/17b5f73)) +* improve get peer info errors ([714b6ec](https://github.com/libp2p/js-libp2p/commit/714b6ec)) +* start kad dht random walk ([#251](https://github.com/libp2p/js-libp2p/issues/251)) ([dd934b9](https://github.com/libp2p/js-libp2p/commit/dd934b9)) + +### Features + +* add datastore to config ([40e840d](https://github.com/libp2p/js-libp2p/commit/40e840d)) +* add delegated peer and content routing support ([#242](https://github.com/libp2p/js-libp2p/issues/242)) ([a95389a](https://github.com/libp2p/js-libp2p/commit/a95389a)) +* add maxNumProviders to findprovs ([#283](https://github.com/libp2p/js-libp2p/issues/283)) ([970deec](https://github.com/libp2p/js-libp2p/commit/970deec)) +* conditionally emit errors ([f71fdfd](https://github.com/libp2p/js-libp2p/commit/f71fdfd)) +* enable relay by default (no hop) ([#254](https://github.com/libp2p/js-libp2p/issues/254)) ([686379e](https://github.com/libp2p/js-libp2p/commit/686379e)) +* make libp2p a state machine ([#257](https://github.com/libp2p/js-libp2p/issues/257)) ([0b75f99](https://github.com/libp2p/js-libp2p/commit/0b75f99)) +* use package-table vs custom script ([a63432e](https://github.com/libp2p/js-libp2p/commit/a63432e)) + + +## [0.23.1](https://github.com/libp2p/js-libp2p/compare/v0.23.0...v0.23.1) (2018-08-13) + + +### Bug Fixes + +* callback with error for invalid or non-peer multiaddr ([#232](https://github.com/libp2p/js-libp2p/issues/232)) ([c8a86db](https://github.com/libp2p/js-libp2p/commit/c8a86db)) + + + + +# [0.23.0](https://github.com/libp2p/js-libp2p/compare/v0.22.0...v0.23.0) (2018-07-27) + + +### Bug Fixes + +* start and stop connection manager with libp2p ([6106915](https://github.com/libp2p/js-libp2p/commit/6106915)) + + +### Features + +* add check for protector and enforced pnet ([2b7cc55](https://github.com/libp2p/js-libp2p/commit/2b7cc55)) + + + + +# [0.22.0](https://github.com/libp2p/js-libp2p/compare/v0.21.0...v0.22.0) (2018-06-29) + + +### Bug Fixes + +* add null property guards ([80f0b60](https://github.com/libp2p/js-libp2p/commit/80f0b60)) +* do not mutate the config object ([ac5cacb](https://github.com/libp2p/js-libp2p/commit/ac5cacb)) +* remove .only ([be9eafe](https://github.com/libp2p/js-libp2p/commit/be9eafe)) +* remove peer discovery module config checks ([4ad70ef](https://github.com/libp2p/js-libp2p/commit/4ad70ef)) +* typo in fixture and fail for correct reason ([1af5ba9](https://github.com/libp2p/js-libp2p/commit/1af5ba9)) + + +### Features + +* enable peer discovery modules by default ([e320854](https://github.com/libp2p/js-libp2p/commit/e320854)) + + + + +# [0.21.0](https://github.com/libp2p/js-libp2p/compare/v0.20.4...v0.21.0) (2018-06-28) + + +### Bug Fixes + +* lock wrtc to 0.1.1 ([6507379](https://github.com/libp2p/js-libp2p/commit/6507379)) + + +### Features + +* (BREAKING CHANGE) overhaul libp2p config and constructor ([6905f1b](https://github.com/libp2p/js-libp2p/commit/6905f1b)) +* set and hook up libp2p-connection-manager ([#184](https://github.com/libp2p/js-libp2p/issues/184)) ([d597204](https://github.com/libp2p/js-libp2p/commit/d597204)) + + + + +## [0.20.4](https://github.com/libp2p/js-libp2p/compare/v0.20.2...v0.20.4) (2018-04-30) + + + + +## [0.20.3](https://github.com/libp2p/js-libp2p/compare/v0.20.2...v0.20.3) (2018-04-30) + + + + +## [0.20.2](https://github.com/libp2p/js-libp2p/compare/v0.20.1...v0.20.2) (2018-04-10) + + + + +## [0.20.1](https://github.com/libp2p/js-libp2p/compare/v0.20.0...v0.20.1) (2018-04-10) + + + + +# [0.20.0](https://github.com/libp2p/js-libp2p/compare/v0.19.2...v0.20.0) (2018-04-06) + + +### Features + +* use class-is for type checks ([bb0c990](https://github.com/libp2p/js-libp2p/commit/bb0c990)) + + + + +## [0.19.2](https://github.com/libp2p/js-libp2p/compare/v0.19.0...v0.19.2) (2018-03-28) + + + + +## [0.19.1](https://github.com/libp2p/js-libp2p/compare/v0.19.0...v0.19.1) (2018-03-28) + + + + +# [0.19.0](https://github.com/libp2p/js-libp2p/compare/v0.18.0...v0.19.0) (2018-03-15) + + + + +# [0.18.0](https://github.com/libp2p/js-libp2p/compare/v0.17.0...v0.18.0) (2018-02-19) + + + + +# [0.17.0](https://github.com/libp2p/js-libp2p/compare/v0.16.5...v0.17.0) (2018-02-16) + + +### Bug Fixes + +* use correct reference to floodSub ([947eaf1](https://github.com/libp2p/js-libp2p/commit/947eaf1)) + + +### Features + +* add pubsub to libp2p ([0c543b7](https://github.com/libp2p/js-libp2p/commit/0c543b7)) + + + + +## [0.16.5](https://github.com/libp2p/js-libp2p/compare/v0.16.4...v0.16.5) (2018-02-14) + + + + +## [0.16.4](https://github.com/libp2p/js-libp2p/compare/v0.16.3...v0.16.4) (2018-02-09) + + + + +## [0.16.3](https://github.com/libp2p/js-libp2p/compare/v0.16.2...v0.16.3) (2018-02-08) + + + + +## [0.16.2](https://github.com/libp2p/js-libp2p/compare/v0.16.1...v0.16.2) (2018-02-07) + + + + +## [0.16.1](https://github.com/libp2p/js-libp2p/compare/v0.16.0...v0.16.1) (2018-02-07) + + + + +# [0.16.0](https://github.com/libp2p/js-libp2p/compare/v0.15.2...v0.16.0) (2018-02-07) + + +### Features + +* add explicit error for case peer id not included in multiaddr ([#155](https://github.com/libp2p/js-libp2p/issues/155)) ([bd8a35a](https://github.com/libp2p/js-libp2p/commit/bd8a35a)) +* dialProtocol and small refactor ([6651401](https://github.com/libp2p/js-libp2p/commit/6651401)) +* use libp2p-switch ([23e8293](https://github.com/libp2p/js-libp2p/commit/23e8293)) + + + + +## [0.15.2](https://github.com/libp2p/js-libp2p/compare/v0.15.1...v0.15.2) (2018-01-28) + + + + +## [0.15.1](https://github.com/libp2p/js-libp2p/compare/v0.15.0...v0.15.1) (2018-01-16) + + +### Bug Fixes + +* typo in DHT setup ([#151](https://github.com/libp2p/js-libp2p/issues/151)) ([61bebd1](https://github.com/libp2p/js-libp2p/commit/61bebd1)) + + + + +# [0.15.0](https://github.com/libp2p/js-libp2p/compare/v0.14.3...v0.15.0) (2018-01-07) + + + + +## [0.14.3](https://github.com/libp2p/js-libp2p/compare/v0.14.2...v0.14.3) (2017-12-15) + + + + +## [0.14.2](https://github.com/libp2p/js-libp2p/compare/v0.14.1...v0.14.2) (2017-12-15) + + + + +## [0.14.1](https://github.com/libp2p/js-libp2p/compare/v0.14.0...v0.14.1) (2017-12-15) + + +### Bug Fixes + +* prevent "The libp2p node is not started yet" when stopping ([#138](https://github.com/libp2p/js-libp2p/issues/138)) ([c88eaf4](https://github.com/libp2p/js-libp2p/commit/c88eaf4)) + + + + +# [0.14.0](https://github.com/libp2p/js-libp2p/compare/v0.13.3...v0.14.0) (2017-12-14) + + +### Bug Fixes + +* remove innactive multiaddrs ([#131](https://github.com/libp2p/js-libp2p/issues/131)) ([1b7360f](https://github.com/libp2p/js-libp2p/commit/1b7360f)) + + + + +## [0.13.3](https://github.com/libp2p/js-libp2p/compare/v0.13.2...v0.13.3) (2017-12-01) + + + + +## [0.13.2](https://github.com/libp2p/js-libp2p/compare/v0.13.1...v0.13.2) (2017-11-27) + + +### Features + +* Bring libp2p-websocket-star to the Transports family! 🌟 ([#122](https://github.com/libp2p/js-libp2p/issues/122)) ([95f029e](https://github.com/libp2p/js-libp2p/commit/95f029e)) + + + + +## [0.13.1](https://github.com/libp2p/js-libp2p/compare/v0.13.0...v0.13.1) (2017-11-12) + + + + +# [0.13.0](https://github.com/libp2p/js-libp2p/compare/v0.12.4...v0.13.0) (2017-10-26) + + +### Features + +* enable and test Circuit Relay ([29cc0af](https://github.com/libp2p/js-libp2p/commit/29cc0af)) + + + + +## [0.12.4](https://github.com/libp2p/js-libp2p/compare/v0.12.3...v0.12.4) (2017-09-07) + + + + +## [0.12.3](https://github.com/libp2p/js-libp2p/compare/v0.12.2...v0.12.3) (2017-09-07) + + + + +## [0.12.2](https://github.com/libp2p/js-libp2p/compare/v0.12.0...v0.12.2) (2017-09-07) + + + + +## [0.12.1](https://github.com/libp2p/js-libp2p/compare/v0.12.0...v0.12.1) (2017-09-07) + + + + +# [0.12.0](https://github.com/libp2p/js-libp2p/compare/v0.11.0...v0.12.0) (2017-09-03) + + +### Features + +* p2p addrs situation ([#119](https://github.com/libp2p/js-libp2p/issues/119)) ([cad173e](https://github.com/libp2p/js-libp2p/commit/cad173e)) + + + + +# [0.11.0](https://github.com/libp2p/js-libp2p/compare/v0.10.2...v0.11.0) (2017-07-22) + + + + +## [0.10.2](https://github.com/libp2p/js-libp2p/compare/v0.10.1...v0.10.2) (2017-07-21) + + +### Bug Fixes + +* circle ci, thanks victor! ([4224c1f](https://github.com/libp2p/js-libp2p/commit/4224c1f)) + + + + +## [0.10.1](https://github.com/libp2p/js-libp2p/compare/v0.10.0...v0.10.1) (2017-07-10) + + + + +# [0.10.0](https://github.com/libp2p/js-libp2p/compare/v0.9.1...v0.10.0) (2017-07-07) + + +### Bug Fixes + +* added missing dep async ([45b0f61](https://github.com/libp2p/js-libp2p/commit/45b0f61)) + + +### Features + +* state events and query changes ([#100](https://github.com/libp2p/js-libp2p/issues/100)) ([73f2f6d](https://github.com/libp2p/js-libp2p/commit/73f2f6d)) + + + + +## [0.9.1](https://github.com/libp2p/js-libp2p/compare/v0.9.0...v0.9.1) (2017-04-16) + + +### Bug Fixes + +* do not use assert in async funcs ([#88](https://github.com/libp2p/js-libp2p/issues/88)) ([2e326e1](https://github.com/libp2p/js-libp2p/commit/2e326e1)) + + + + +# [0.9.0](https://github.com/libp2p/js-libp2p/compare/v0.8.0...v0.9.0) (2017-04-06) + + + + +# [0.8.0](https://github.com/libp2p/js-libp2p/compare/v0.7.0...v0.8.0) (2017-03-31) + + +### Bug Fixes + +* addition of ipfs id appendix must come before transport filtering ([291e79f](https://github.com/libp2p/js-libp2p/commit/291e79f)) +* avoid deleting nodes from peerBook ([300936f](https://github.com/libp2p/js-libp2p/commit/300936f)) +* correct method on peer-book ([031ecb3](https://github.com/libp2p/js-libp2p/commit/031ecb3)) + + +### Features + +* append peer id to multiaddr if not there ([59ea9c3](https://github.com/libp2p/js-libp2p/commit/59ea9c3)) +* not remove peer from peerBook on disconnect ([a4b41b0](https://github.com/libp2p/js-libp2p/commit/a4b41b0)) + + + + +# [0.7.0](https://github.com/libp2p/js-libp2p/compare/v0.6.2...v0.7.0) (2017-03-29) + + +### Features + +* update events to conform with [#74](https://github.com/libp2p/js-libp2p/issues/74) ([f73c045](https://github.com/libp2p/js-libp2p/commit/f73c045)) + + + + +## [0.6.2](https://github.com/libp2p/js-libp2p/compare/v0.6.1...v0.6.2) (2017-03-28) + + + + +## [0.6.1](https://github.com/libp2p/js-libp2p/compare/v0.6.0...v0.6.1) (2017-03-27) + + + + +# [0.6.0](https://github.com/libp2p/js-libp2p/compare/v0.5.5...v0.6.0) (2017-03-27) + + +### Bug Fixes + +* last touches ([2c23d9a](https://github.com/libp2p/js-libp2p/commit/2c23d9a)) + + +### Features + +* new super simplified API ([a6623c1](https://github.com/libp2p/js-libp2p/commit/a6623c1)) + + + + +## [0.5.5](https://github.com/libp2p/js-libp2p/compare/v0.5.4...v0.5.5) (2017-03-21) diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/CODE_OF_CONDUCT.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..6b0fa54c5 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/CODE_OF_CONDUCT.md @@ -0,0 +1,3 @@ +# Contributor Code of Conduct + +This project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md) diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/LICENSE-APACHE b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/LICENSE-APACHE new file mode 100644 index 000000000..b09cd7856 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/LICENSE-APACHE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/LICENSE-MIT b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/LICENSE-MIT new file mode 100644 index 000000000..72dc60d84 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/LICENSE-MIT @@ -0,0 +1,19 @@ +The MIT License (MIT) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/README.md new file mode 100644 index 000000000..369d3ebe8 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/README.md @@ -0,0 +1,161 @@ +

+ libp2p hex logo +

+ +

The JavaScript implementation of the libp2p Networking Stack

+ +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![npm](https://img.shields.io/npm/dm/libp2p.svg?style=flat-square)](https://www.npmjs.com/package/libp2p) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![Matrix](https://img.shields.io/badge/matrix-%23libp2p--implementers%3Aipfs.io-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23libp2p) +[![Discord](https://img.shields.io/discord/806902334369824788?color=blueviolet\&label=discord\&style=flat-square)](https://discord.com/invite/Ae4TbahHaT) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +# Background + +libp2p is the product of a long and arduous quest to understand the evolution of the Internet networking stack. In order to build P2P applications, devs have long had to make custom ad-hoc solutions to fit their needs, sometimes making some hard assumptions about their runtimes and the state of the network at the time of their development. Today, looking back more than 20 years, we see a clear pattern in the types of mechanisms built around the Internet Protocol, IP, which can be found throughout many layers of the OSI layer system, libp2p distils these mechanisms into flat categories and defines clear interfaces that once exposed, enable other protocols and applications to use and swap them, enabling upgradability and adaptability for the runtime, without breaking the API. + +We are in the process of writing better documentation, blog posts, tutorials and a formal specification. Today you can find: + +- [libp2p.io](https://libp2p.io) +- [docs.libp2p.io](https://docs.libp2p.io) +- [Specification (WIP)](https://github.com/libp2p/specs) +- [Discussion Forums](https://discuss.libp2p.io) +- Talks + - [`libp2p <3 ethereum` at DEVCON2](https://archive.devcon.org/archive/watch/2/libp2p-devp2p-ipfs-and-ethereum-networking/) +- Articles + - [The overview of libp2p](https://github.com/libp2p/libp2p#description) + +To sum up, libp2p is a "network stack" -- a protocol suite -- that cleanly separates concerns, and enables sophisticated applications to only use the protocols they absolutely need, without giving up interoperability and upgradability. libp2p grew out of IPFS, but it is built so that lots of people can use it, for lots of different projects. + +# Roadmap + +The js-libp2p roadmap can be found here: + +It represents current projects the js-libp2p maintainers are focused on and provides an estimation of completion targets. + +# Usage + +### Configuration + +For all the information on how you can configure libp2p see [CONFIGURATION.md](https://github.com/libp2p/js-libp2p/blob/main/doc/CONFIGURATION.md). + +## Limits + +For help configuring your node to resist malicious network peers, see [LIMITS.md](https://github.com/libp2p/js-libp2p/blob/main/doc/LIMITS.md) + +## Getting started + +If you are starting your journey with `js-libp2p`, read the [GETTING\_STARTED.md](https://github.com/libp2p/js-libp2p/blob/main/doc/GETTING_STARTED.md) guide. + +## Tutorials and Examples + +You can find multiple examples on the [examples repo](https://github.com/libp2p/js-libp2p-examples) that will guide you through using libp2p for several scenarios. + +# Development + +**Clone and install dependencies:** + +```sh +> git clone https://github.com/libp2p/js-libp2p.git +> cd js-libp2p +> npm install +> npm run build +``` + +# Tests + +## Run unit tests + +```sh +# run all the unit tests +> npm test + +# run just Node.js tests +> npm run test:node + +# run just Browser tests (Chrome) +> npm run test:chrome +``` + +# Packages + +List of packages currently in existence for libp2p + +> This table is generated using the module `package-table` with `package-table --data=package-list.json`. + +| Package | Version | Deps | CI | Coverage | +| ------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **libp2p** | | | | | +| [`libp2p`](//github.com/libp2p/js-libp2p) | [![npm](https://img.shields.io/npm/v/libp2p.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/libp2p?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/libp2p) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) | +| [`@libp2p/interface`](//github.com/libp2p/js-libp2p/tree/main/packages/interface) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Finterface.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/interface/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Finterface?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Finterface) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/interface/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/interface/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/interface/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/interface) | +| **transports** | | | | | +| [`@libp2p/tcp`](//github.com/libp2p/js-libp2p/tree/main/packages/transport-tcp) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Ftcp.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-tcp/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Ftcp?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Ftcp) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/transport-tcp/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-tcp/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-tcp/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-tcp) | +| [`@libp2p/webrtc`](//github.com/libp2p/js-libp2p/tree/main/packages/transport-webrtc) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebrtc.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-webrtc/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebrtc?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebrtc) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/transport-webrtc/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-webrtc/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-webrtc/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-webrtc) | +| [`@libp2p/websockets`](//github.com/libp2p/js-libp2p/tree/main/packages/transport-websockets) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebsockets.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-websockets/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebsockets?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebsockets) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/transport-websockets/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-websockets/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-websockets/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-websockets) | +| [`@libp2p/webtransport`](//github.com/libp2p/js-libp2p/tree/main/packages/transport-webtransport) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fwebtransport.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-webtransport/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fwebtransport?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fwebtransport) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/transport-webtransport/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/transport-webtransport/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-webtransport/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/transport-webtransport) | +| **secure channels** | | | | | +| [`@chainsafe/libp2p-noise`](//github.com/ChainSafe/js-libp2p-noise) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Flibp2p-noise.svg?maxAge=86400\&style=flat-square)](//github.com/ChainSafe/js-libp2p-noise/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Flibp2p-noise?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40chainsafe%2Flibp2p-noise) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-noise/js-test-and-release.yml?branch=master\&label=ci\&style=flat-square)](//github.com/ChainSafe/js-libp2p-noise/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-noise/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-noise) | +| [`@libp2p/plaintext`](//github.com/libp2p/js-libp2p/tree/main/packages/connection-encrypter-plaintext) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fplaintext.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/connection-encrypter-plaintext/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fplaintext?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fplaintext) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/connection-encrypter-plaintext/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/connection-encrypter-plaintext/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/connection-encrypter-plaintext/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/connection-encrypter-plaintext) | +| **stream multiplexers** | | | | | +| [`@libp2p/mplex`](//github.com/libp2p/js-libp2p/tree/main/packages/stream-multiplexer-mplex) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fmplex.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/stream-multiplexer-mplex/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fmplex?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fmplex) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/stream-multiplexer-mplex/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/stream-multiplexer-mplex/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/stream-multiplexer-mplex/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/stream-multiplexer-mplex) | +| [`@chainsafe/libp2p-yamux`](//github.com/ChainSafe/js-libp2p-yamux) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Flibp2p-yamux.svg?maxAge=86400\&style=flat-square)](//github.com/ChainSafe/js-libp2p-yamux/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Flibp2p-yamux?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40chainsafe%2Flibp2p-yamux) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-yamux/js-test-and-release.yml?branch=master\&label=ci\&style=flat-square)](//github.com/ChainSafe/js-libp2p-yamux/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-yamux/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-yamux) | +| **peer discovery** | | | | | +| [`@libp2p/bootstrap`](//github.com/libp2p/js-libp2p/tree/main/packages/peer-discovery-bootstrap) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fbootstrap.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-discovery-bootstrap/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fbootstrap?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fbootstrap) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/peer-discovery-bootstrap/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-discovery-bootstrap/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-discovery-bootstrap/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-discovery-bootstrap) | +| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/kad-dht/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/kad-dht/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/kad-dht) | +| [`@libp2p/mdns`](//github.com/libp2p/js-libp2p/tree/main/packages/peer-discovery-mdns) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fmdns.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-discovery-mdns/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fmdns?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fmdns) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/peer-discovery-mdns/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-discovery-mdns/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-discovery-mdns/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-discovery-mdns) | +| [`@chainsafe/discv5`](//github.com/ChainSafe/discv5) | [![npm](https://img.shields.io/npm/v/%40chainsafe%2Fdiscv5.svg?maxAge=86400\&style=flat-square)](//github.com/ChainSafe/discv5/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40chainsafe%2Fdiscv5?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40chainsafe%2Fdiscv5) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/discv5/test_and_release.yml?branch=master\&label=ci\&style=flat-square)](//github.com/ChainSafe/discv5/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/discv5/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/discv5) | +| **content routing** | | | | | +| [`@libp2p/http-v1-content-routing`](//github.com/libp2p/js-http-v1-content-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fhttp-v1-content-routing.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-http-v1-content-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fhttp-v1-content-routing?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fhttp-v1-content-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-http-v1-content-routing/js-test-and-release.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-http-v1-content-routing/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-http-v1-content-routing/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-http-v1-content-routing) | +| [`@libp2p/delegated-content-routing`](//github.com/libp2p/js-libp2p-delegated-content-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fdelegated-content-routing.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fdelegated-content-routing?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fdelegated-content-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-delegated-content-routing/js-test-and-release.yml?branch=master\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing) | +| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/kad-dht/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/kad-dht/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/kad-dht) | +| **peer routing** | | | | | +| [`@libp2p/delegated-peer-routing`](//github.com/libp2p/js-libp2p-delegated-peer-routing) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fdelegated-peer-routing.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fdelegated-peer-routing?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fdelegated-peer-routing) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-delegated-peer-routing/js-test-and-release.yml?branch=master\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing) | +| [`@libp2p/kad-dht`](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fkad-dht.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fkad-dht?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fkad-dht) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/kad-dht/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/kad-dht/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/kad-dht/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/kad-dht) | +| **utilities** | | | | | +| [`@libp2p/crypto`](//github.com/libp2p/js-libp2p/tree/main/packages/crypto) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fcrypto.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/crypto/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fcrypto?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fcrypto) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/crypto/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/crypto/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/crypto/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/crypto) | +| **data types** | | | | | +| [`@libp2p/peer-id`](//github.com/libp2p/js-libp2p/tree/main/packages/peer-id) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fpeer-id.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-id/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fpeer-id?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fpeer-id) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/peer-id/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-id/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-id/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-id) | +| [`@libp2p/peer-record`](//github.com/libp2p/js-libp2p/tree/main/packages/peer-record) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Fpeer-record.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-record/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Fpeer-record?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Fpeer-record) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/peer-record/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/peer-record/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-record/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/peer-record) | +| **pubsub** | | | | | +| [`@ChainSafe/libp2p-gossipsub`](//github.com/ChainSafe/js-libp2p-gossipsub) | [![npm](https://img.shields.io/npm/v/%40ChainSafe%2Flibp2p-gossipsub.svg?maxAge=86400\&style=flat-square)](//github.com/ChainSafe/js-libp2p-gossipsub/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40ChainSafe%2Flibp2p-gossipsub?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40ChainSafe%2Flibp2p-gossipsub) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-gossipsub/main.yml?branch=master\&label=ci\&style=flat-square)](//github.com/ChainSafe/js-libp2p-gossipsub/actions?query=branch%3Amaster+workflow%3Aci+) | [![codecov](https://codecov.io/gh/ChainSafe/js-libp2p-gossipsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-gossipsub) | +| [`@libp2p/floodsub`](//github.com/libp2p/js-libp2p/tree/main/packages/pubsub-floodsub) | [![npm](https://img.shields.io/npm/v/%40libp2p%2Ffloodsub.svg?maxAge=86400\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/pubsub-floodsub/releases) | [![Deps](https://img.shields.io/librariesio/release/npm/%40libp2p%2Ffloodsub?logo=Libraries.io\&logoColor=white\&style=flat-square)](//libraries.io/npm/%40libp2p%2Ffloodsub) | [![GitHub CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/tree/main/packages/pubsub-floodsub/main.yml?branch=main\&label=ci\&style=flat-square)](//github.com/libp2p/js-libp2p/tree/main/packages/pubsub-floodsub/actions?query=branch%3Amain+workflow%3Aci+) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/pubsub-floodsub/branch/main/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p/tree/main/packages/pubsub-floodsub) | + +# Used by + +
+

+ + HOPR Logo + Helia logo + OrbitDB logo + Waku + Peerbit logo +

+
+ +And [many others...](https://github.com/libp2p/js-libp2p/network/dependents) + +# Contribute + +The libp2p implementation in JavaScript is a work in progress. As such, there are a few things you can do right now to help out: + +- Go through the modules and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically. +- **Perform code reviews**. More eyes will help a) speed the project along b) ensure quality and c) reduce possible future bugs. +- **Add tests**. There can never be enough tests. + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/libp2p/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/libp2p/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/package-list.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/package-list.json new file mode 100644 index 000000000..80fb13495 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/package-list.json @@ -0,0 +1,53 @@ +{ + "columns": [ + "Package", + "Version", + "Deps", + "CI", + "Coverage" + ], + "rows": [ + "libp2p", + ["libp2p/js-libp2p", "libp2p", "main", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/interface", "@libp2p/interface", "main", "main.yml"], + + "transports", + ["libp2p/js-libp2p/tree/main/packages/transport-tcp", "@libp2p/tcp", "main", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/transport-webrtc", "@libp2p/webrtc", "main", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/transport-websockets", "@libp2p/websockets", "main", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/transport-webtransport", "@libp2p/webtransport", "main", "main.yml"], + + "secure channels", + ["ChainSafe/js-libp2p-noise", "@chainsafe/libp2p-noise", "master", "js-test-and-release.yml"], + ["libp2p/js-libp2p/tree/main/packages/connection-encrypter-plaintext", "@libp2p/plaintext", "main", "main.yml"], + + "stream multiplexers", + ["ChainSafe/js-libp2p-yamux", "@chainsafe/libp2p-yamux", "master", "js-test-and-release.yml"], + + "peer discovery", + ["libp2p/js-libp2p/tree/main/packages/peer-discovery-bootstrap", "@libp2p/bootstrap", "main", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/kad-dht", "@libp2p/kad-dht", "main", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/peer-discovery-mdns", "@libp2p/mdns", "main", "main.yml"], + ["ChainSafe/discv5", "@chainsafe/discv5", "master", "test_and_release.yml"], + + "content routing", + ["libp2p/js-http-v1-content-routing", "@libp2p/http-v1-content-routing", "main", "js-test-and-release.yml"], + ["libp2p/js-libp2p-delegated-content-routing", "@libp2p/delegated-content-routing", "master", "js-test-and-release.yml"], + ["libp2p/js-libp2p/tree/main/packages/kad-dht", "@libp2p/kad-dht", "main", "main.yml"], + + "peer routing", + ["libp2p/js-libp2p-delegated-peer-routing", "@libp2p/delegated-peer-routing", "master", "js-test-and-release.yml"], + ["libp2p/js-libp2p/tree/main/packages/kad-dht", "@libp2p/kad-dht", "main", "main.yml"], + + "utilities", + ["libp2p/js-libp2p/tree/main/packages/crypto", "@libp2p/crypto", "main", "main.yml"], + + "data types", + ["libp2p/js-libp2p/tree/main/packages/peer-id", "@libp2p/peer-id", "main", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/peer-record", "@libp2p/peer-record", "main", "main.yml"], + + "pubsub", + ["ChainSafe/js-libp2p-gossipsub", "@ChainSafe/libp2p-gossipsub", "master", "main.yml"], + ["libp2p/js-libp2p/tree/main/packages/pubsub-floodsub", "@libp2p/floodsub", "main", "main.yml"] + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/package.json new file mode 100644 index 000000000..67050a1ec --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/package.json @@ -0,0 +1,121 @@ +{ + "name": "libp2p", + "version": "2.9.0", + "description": "JavaScript implementation of libp2p, a modular peer to peer network stack", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/libp2p#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "IPFS", + "libp2p", + "network", + "p2p", + "peer", + "peer-to-peer" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "typesVersions": { + "*": { + "*": [ + "*", + "dist/*", + "dist/src/*", + "dist/src/*/index" + ], + "src/*": [ + "*", + "dist/*", + "dist/src/*", + "dist/src/*/index" + ] + } + }, + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + }, + "./user-agent": { + "types": "./dist/src/user-agent.d.ts", + "browser": "./dist/src/user-agent.browser.js", + "import": "./dist/src/user-agent.js" + }, + "./version": { + "types": "./dist/src/version.d.ts", + "import": "./dist/src/version.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "prepublishOnly": "node scripts/update-version.js && npm run build", + "build": "aegir build", + "test": "aegir test", + "test:node": "aegir test -t node --cov", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:webkit": "aegir test -t browser -- --browser webkit" + }, + "dependencies": { + "@types/react-native": "^0.73.0", + "@chainsafe/is-ip": "^2.1.0", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "@libp2p/interface-internal": "^2.3.18", + "@libp2p/logger": "^5.1.21", + "@libp2p/multistream-select": "^6.0.28", + "@libp2p/peer-collections": "^6.0.34", + "@libp2p/peer-id": "^5.1.8", + "@libp2p/peer-store": "^11.2.6", + "@libp2p/utils": "^6.7.1", + "@multiformats/dns": "^1.0.6", + "@multiformats/multiaddr": "^12.4.4", + "@multiformats/multiaddr-matcher": "^2.0.0", + "any-signal": "^4.1.1", + "datastore-core": "^10.0.2", + "interface-datastore": "^8.3.1", + "it-merge": "^3.0.11", + "it-parallel": "^3.0.11", + "main-event": "^1.0.1", + "multiformats": "^13.3.6", + "p-defer": "^4.0.1", + "p-retry": "^6.2.1", + "progress-events": "^1.0.1", + "race-event": "^1.6.0", + "race-signal": "^1.1.3", + "uint8arrays": "^5.1.0" + }, + "browser": { + "./dist/src/connection-manager/constants.js": "./dist/src/connection-manager/constants.browser.js", + "./dist/src/config/connection-gater.js": "./dist/src/config/connection-gater.browser.js", + "./dist/src/user-agent.js": "./dist/src/user-agent.browser.js" + }, + "react-native": { + "./dist/src/connection-manager/constants.js": "./dist/src/connection-manager/constants.browser.js", + "./dist/src/config/connection-gater.js": "./dist/src/config/connection-gater.browser.js", + "./dist/src/user-agent.js": "./dist/src/user-agent.react-native.js" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/scripts/update-version.js b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/scripts/update-version.js new file mode 100644 index 000000000..5ea6bec7b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/scripts/update-version.js @@ -0,0 +1,14 @@ +import { readFile, writeFile } from 'fs/promises' + +const pkg = JSON.parse( + await readFile( + new URL('../package.json', import.meta.url) + ) +) + +await writeFile( + new URL('../src/version.ts', import.meta.url), + `export const version = '${pkg.version}' +export const name = 'js-${pkg.name}' +` +) diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/dns-mappings.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/dns-mappings.ts new file mode 100644 index 000000000..24f46f50d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/dns-mappings.ts @@ -0,0 +1,185 @@ +import { isPrivateIp, trackedMap } from '@libp2p/utils' +import { multiaddr, protocols } from '@multiformats/multiaddr' +import type { AddressManagerComponents, AddressManagerInit } from './index.js' +import type { Logger } from '@libp2p/interface' +import type { NodeAddress } from '@libp2p/interface-internal' +import type { Multiaddr, StringTuple } from '@multiformats/multiaddr' + +const MAX_DATE = 8_640_000_000_000_000 + +export const defaultValues = { + maxObservedAddresses: 10 +} + +interface DNSMapping { + domain: string + verified: boolean + expires: number + lastVerified?: number +} + +const CODEC_TLS = 0x01c0 +const CODEC_SNI = 0x01c1 +const CODEC_DNS = 0x35 +const CODEC_DNS4 = 0x36 +const CODEC_DNS6 = 0x37 +const CODEC_DNSADDR = 0x38 + +export class DNSMappings { + private readonly log: Logger + private readonly mappings: Map + + constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) { + this.log = components.logger.forComponent('libp2p:address-manager:dns-mappings') + this.mappings = trackedMap({ + name: 'libp2p_address_manager_dns_mappings', + metrics: components.metrics + }) + } + + has (ma: Multiaddr): boolean { + const host = this.findHost(ma) + + for (const mapping of this.mappings.values()) { + if (mapping.domain === host) { + return true + } + } + + return false + } + + add (domain: string, addresses: string[]): void { + addresses.forEach(ip => { + this.log('add DNS mapping %s to %s', ip, domain) + // we are only confident if this is an local domain mapping, otherwise + // we will require external validation + const verified = isPrivateIp(ip) === true + + this.mappings.set(ip, { + domain, + verified, + expires: verified ? MAX_DATE - Date.now() : 0, + lastVerified: verified ? MAX_DATE - Date.now() : undefined + }) + }) + } + + remove (ma: Multiaddr): boolean { + const host = this.findHost(ma) + let wasConfident = false + + for (const [ip, mapping] of this.mappings.entries()) { + if (mapping.domain === host) { + this.log('removing %s to %s DNS mapping %e', ip, mapping.domain) + this.mappings.delete(ip) + wasConfident = wasConfident || mapping.verified + } + } + + return wasConfident + } + + getAll (addresses: NodeAddress[]): NodeAddress[] { + const dnsMappedAddresses: NodeAddress[] = [] + + for (let i = 0; i < addresses.length; i++) { + const address = addresses[i] + const tuples = address.multiaddr.stringTuples() + const host = tuples[0][1] + + if (host == null) { + continue + } + + for (const [ip, mapping] of this.mappings.entries()) { + if (host !== ip) { + continue + } + + // insert SNI tuple after TLS tuple, if one is present + const mappedIp = this.maybeAddSNITuple(tuples, mapping.domain) + + if (mappedIp) { + // remove the address and replace it with the version that includes + // the SNI tuple + addresses.splice(i, 1) + i-- + + dnsMappedAddresses.push({ + multiaddr: multiaddr(`/${ + tuples.map(tuple => { + return [ + protocols(tuple[0]).name, + tuple[1] + ].join('/') + }).join('/') + }`), + verified: mapping.verified, + type: 'dns-mapping', + expires: mapping.expires, + lastVerified: mapping.lastVerified + }) + } + } + } + + return dnsMappedAddresses + } + + private maybeAddSNITuple (tuples: StringTuple[], domain: string): boolean { + for (let j = 0; j < tuples.length; j++) { + if (tuples[j][0] === CODEC_TLS && tuples[j + 1]?.[0] !== CODEC_SNI) { + tuples.splice(j + 1, 0, [CODEC_SNI, domain]) + return true + } + } + + return false + } + + confirm (ma: Multiaddr, ttl: number): boolean { + const host = this.findHost(ma) + let startingConfidence = false + + for (const [ip, mapping] of this.mappings.entries()) { + if (mapping.domain === host) { + this.log('marking %s to %s DNS mapping as verified', ip, mapping.domain) + startingConfidence = mapping.verified + mapping.verified = true + mapping.expires = Date.now() + ttl + mapping.lastVerified = Date.now() + } + } + + return startingConfidence + } + + unconfirm (ma: Multiaddr, ttl: number): boolean { + const host = this.findHost(ma) + let wasConfident = false + + for (const [ip, mapping] of this.mappings.entries()) { + if (mapping.domain === host) { + this.log('removing verification of %s to %s DNS mapping', ip, mapping.domain) + wasConfident = wasConfident || mapping.verified + mapping.verified = false + mapping.expires = Date.now() + ttl + } + } + + return wasConfident + } + + private findHost (ma: Multiaddr): string | undefined { + for (const tuple of ma.stringTuples()) { + if (tuple[0] === CODEC_SNI) { + return tuple[1] + } + + if (tuple[0] === CODEC_DNS || tuple[0] === CODEC_DNS4 || tuple[0] === CODEC_DNS6 || tuple[0] === CODEC_DNSADDR) { + return tuple[1] + } + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/index.ts new file mode 100644 index 000000000..d8c044761 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/index.ts @@ -0,0 +1,541 @@ +/* eslint-disable complexity */ +import { isIPv4 } from '@chainsafe/is-ip' +import { peerIdFromString } from '@libp2p/peer-id' +import { debounce, createScalableCuckooFilter, isPrivateIp } from '@libp2p/utils' +import { multiaddr } from '@multiformats/multiaddr' +import { QUIC_V1, TCP, WebSockets, WebSocketsSecure } from '@multiformats/multiaddr-matcher' +import { DNSMappings } from './dns-mappings.js' +import { IPMappings } from './ip-mappings.js' +import { ObservedAddresses } from './observed-addresses.js' +import { TransportAddresses } from './transport-addresses.js' +import type { ComponentLogger, Libp2pEvents, Logger, PeerId, PeerStore, Metrics } from '@libp2p/interface' +import type { AddressManager as AddressManagerInterface, TransportManager, NodeAddress, ConfirmAddressOptions } from '@libp2p/interface-internal' +import type { Filter } from '@libp2p/utils' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { TypedEventTarget } from 'main-event' + +const ONE_MINUTE = 60_000 + +export const defaultValues = { + maxObservedAddresses: 10, + addressVerificationTTL: ONE_MINUTE * 10, + addressVerificationRetry: ONE_MINUTE * 5 +} + +export interface AddressManagerInit { + /** + * Pass an function in this field to override the list of addresses + * that are announced to the network + */ + announceFilter?: AddressFilter + + /** + * A list of string multiaddrs to listen on + */ + listen?: string[] + + /** + * A list of string multiaddrs to use instead of those reported by transports + */ + announce?: string[] + + /** + * A list of string multiaddrs string to never announce + */ + noAnnounce?: string[] + + /** + * A list of string multiaddrs to add to the list of announced addresses + */ + appendAnnounce?: string[] + + /** + * Limits the number of observed addresses we will store + */ + maxObservedAddresses?: number + + /** + * How long before each public address should be reverified in ms. + * + * Requires `@libp2p/autonat` or some other verification method to be + * configured. + * + * @default 600_000 + */ + addressVerificationTTL?: number + + /** + * After a transport or mapped address has failed to verify, how long to wait + * before retrying it in ms + * + * Requires `@libp2p/autonat` or some other verification method to be + * configured. + * + * @default 300_000 + */ + addressVerificationRetry?: number +} + +export interface AddressManagerComponents { + peerId: PeerId + transportManager: TransportManager + peerStore: PeerStore + events: TypedEventTarget + logger: ComponentLogger + metrics?: Metrics +} + +/** + * A function that takes a list of multiaddrs and returns a list + * to announce + */ +export interface AddressFilter { + (addrs: Multiaddr[]): Multiaddr[] +} + +const defaultAddressFilter = (addrs: Multiaddr[]): Multiaddr[] => addrs + +/** + * If the passed multiaddr contains the passed peer id, remove it + */ +function stripPeerId (ma: Multiaddr, peerId: PeerId): Multiaddr { + const observedPeerIdStr = ma.getPeerId() + + // strip our peer id if it has been passed + if (observedPeerIdStr != null) { + const observedPeerId = peerIdFromString(observedPeerIdStr) + + // use same encoding for comparison + if (observedPeerId.equals(peerId)) { + ma = ma.decapsulate(multiaddr(`/p2p/${peerId.toString()}`)) + } + } + + return ma +} + +export class AddressManager implements AddressManagerInterface { + private readonly log: Logger + private readonly components: AddressManagerComponents + // this is an array to allow for duplicates, e.g. multiples of `/ip4/0.0.0.0/tcp/0` + private readonly listen: string[] + private readonly announce: Set + private readonly appendAnnounce: Set + private readonly announceFilter: AddressFilter + private readonly observed: ObservedAddresses + private readonly dnsMappings: DNSMappings + private readonly ipMappings: IPMappings + private readonly transportAddresses: TransportAddresses + private readonly observedAddressFilter: Filter + private readonly addressVerificationTTL: number + private readonly addressVerificationRetry: number + + /** + * Responsible for managing the peer addresses. + * Peers can specify their listen and announce addresses. + * The listen addresses will be used by the libp2p transports to listen for new connections, + * while the announce addresses will be used for the peer addresses' to other peers in the network. + */ + constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) { + const { listen = [], announce = [], appendAnnounce = [] } = init + + this.components = components + this.log = components.logger.forComponent('libp2p:address-manager') + this.listen = listen.map(ma => ma.toString()) + this.announce = new Set(announce.map(ma => ma.toString())) + this.appendAnnounce = new Set(appendAnnounce.map(ma => ma.toString())) + this.observed = new ObservedAddresses(components, init) + this.dnsMappings = new DNSMappings(components, init) + this.ipMappings = new IPMappings(components, init) + this.transportAddresses = new TransportAddresses(components, init) + this.announceFilter = init.announceFilter ?? defaultAddressFilter + this.observedAddressFilter = createScalableCuckooFilter(1024) + this.addressVerificationTTL = init.addressVerificationTTL ?? defaultValues.addressVerificationTTL + this.addressVerificationRetry = init.addressVerificationRetry ?? defaultValues.addressVerificationRetry + + // this method gets called repeatedly on startup when transports start listening so + // debounce it so we don't cause multiple self:peer:update events to be emitted + this._updatePeerStoreAddresses = debounce(this._updatePeerStoreAddresses.bind(this), 1000) + + // update our stored addresses when new transports listen + components.events.addEventListener('transport:listening', () => { + this._updatePeerStoreAddresses() + }) + // update our stored addresses when existing transports stop listening + components.events.addEventListener('transport:close', () => { + this._updatePeerStoreAddresses() + }) + } + + readonly [Symbol.toStringTag] = '@libp2p/address-manager' + + _updatePeerStoreAddresses (): void { + // if announce addresses have been configured, ensure they make it into our peer + // record for things like identify + const addrs = this.getAddresses() + .map(ma => { + // strip our peer id if it is present + if (ma.getPeerId() === this.components.peerId.toString()) { + return ma.decapsulate(`/p2p/${this.components.peerId.toString()}`) + } + + return ma + }) + + this.components.peerStore.patch(this.components.peerId, { + multiaddrs: addrs + }) + .catch(err => { + this.log.error('error updating addresses', err) + }) + } + + /** + * Get peer listen multiaddrs + */ + getListenAddrs (): Multiaddr[] { + return Array.from(this.listen).map((a) => multiaddr(a)) + } + + /** + * Get peer announcing multiaddrs + */ + getAnnounceAddrs (): Multiaddr[] { + return Array.from(this.announce).map((a) => multiaddr(a)) + } + + /** + * Get peer announcing multiaddrs + */ + getAppendAnnounceAddrs (): Multiaddr[] { + return Array.from(this.appendAnnounce).map((a) => multiaddr(a)) + } + + /** + * Get observed multiaddrs + */ + getObservedAddrs (): Multiaddr[] { + return this.observed.getAll().map(addr => addr.multiaddr) + } + + /** + * Add peer observed addresses + */ + addObservedAddr (addr: Multiaddr): void { + const tuples = addr.stringTuples() + const socketAddress = `${tuples[0][1]}:${tuples[1][1]}` + + // ignore if this address if it's been observed before + if (this.observedAddressFilter.has(socketAddress)) { + return + } + + this.observedAddressFilter.add(socketAddress) + + addr = stripPeerId(addr, this.components.peerId) + + // ignore observed address if it is an IP mapping + if (this.ipMappings.has(addr)) { + return + } + + // ignore observed address if it is a DNS mapping + if (this.dnsMappings.has(addr)) { + return + } + + this.observed.add(addr) + } + + confirmObservedAddr (addr: Multiaddr, options?: ConfirmAddressOptions): void { + addr = stripPeerId(addr, this.components.peerId) + let startingConfidence = true + + if (options?.type === 'transport' || this.transportAddresses.has(addr)) { + const transportStartingConfidence = this.transportAddresses.confirm(addr, options?.ttl ?? this.addressVerificationTTL) + + if (!transportStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + + if (options?.type === 'dns-mapping' || this.dnsMappings.has(addr)) { + const dnsMappingStartingConfidence = this.dnsMappings.confirm(addr, options?.ttl ?? this.addressVerificationTTL) + + if (!dnsMappingStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + + if (options?.type === 'ip-mapping' || this.ipMappings.has(addr)) { + const ipMappingStartingConfidence = this.ipMappings.confirm(addr, options?.ttl ?? this.addressVerificationTTL) + + if (!ipMappingStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + + if (options?.type === 'observed' || this.observed.has(addr)) { + // try to match up observed address with local transport listener + if (this.maybeUpgradeToIPMapping(addr)) { + this.ipMappings.confirm(addr, options?.ttl ?? this.addressVerificationTTL) + startingConfidence = false + } else { + const observedStartingConfidence = this.observed.confirm(addr, options?.ttl ?? this.addressVerificationTTL) + + if (!observedStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + } + + // only trigger the 'self:peer:update' event if our confidence in an address has changed + if (!startingConfidence) { + this._updatePeerStoreAddresses() + } + } + + removeObservedAddr (addr: Multiaddr, options?: ConfirmAddressOptions): void { + addr = stripPeerId(addr, this.components.peerId) + + let startingConfidence = false + + if (this.observed.has(addr)) { + const observedStartingConfidence = this.observed.remove(addr) + + if (!observedStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + + if (this.transportAddresses.has(addr)) { + const transportStartingConfidence = this.transportAddresses.unconfirm(addr, options?.ttl ?? this.addressVerificationRetry) + + if (!transportStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + + if (this.dnsMappings.has(addr)) { + const dnsMappingStartingConfidence = this.dnsMappings.unconfirm(addr, options?.ttl ?? this.addressVerificationRetry) + + if (!dnsMappingStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + + if (this.ipMappings.has(addr)) { + const ipMappingStartingConfidence = this.ipMappings.unconfirm(addr, options?.ttl ?? this.addressVerificationRetry) + + if (!ipMappingStartingConfidence && startingConfidence) { + startingConfidence = false + } + } + + // only trigger the 'self:peer:update' event if our confidence in an address has changed + if (startingConfidence) { + this._updatePeerStoreAddresses() + } + } + + getAddresses (): Multiaddr[] { + const addresses = new Set() + + const multiaddrs = this.getAddressesWithMetadata() + .filter(addr => { + if (!addr.verified) { + return false + } + + const maStr = addr.multiaddr.toString() + + if (addresses.has(maStr)) { + return false + } + + addresses.add(maStr) + + return true + }) + .map(address => address.multiaddr) + + // filter addressees before returning + return this.announceFilter( + multiaddrs.map(str => { + const ma = multiaddr(str) + const lastComponent = ma.getComponents().pop() + + if (lastComponent?.value === this.components.peerId.toString()) { + return ma + } + + return ma.encapsulate(`/p2p/${this.components.peerId.toString()}`) + }) + ) + } + + getAddressesWithMetadata (): NodeAddress[] { + const announceMultiaddrs = this.getAnnounceAddrs() + + if (announceMultiaddrs.length > 0) { + // allow transports to add certhashes and other runtime information + this.components.transportManager.getListeners().forEach(listener => { + listener.updateAnnounceAddrs(announceMultiaddrs) + }) + + return announceMultiaddrs.map(multiaddr => ({ + multiaddr, + verified: true, + type: 'announce', + expires: Date.now() + this.addressVerificationTTL, + lastVerified: Date.now() + })) + } + + let addresses: NodeAddress[] = [] + + // add transport addresses + addresses = addresses.concat( + this.components.transportManager.getAddrs() + .map(multiaddr => this.transportAddresses.get(multiaddr, this.addressVerificationTTL)) + ) + + const appendAnnounceMultiaddrs = this.getAppendAnnounceAddrs() + + // add append announce addresses + if (appendAnnounceMultiaddrs.length > 0) { + // allow transports to add certhashes and other runtime information + this.components.transportManager.getListeners().forEach(listener => { + listener.updateAnnounceAddrs(appendAnnounceMultiaddrs) + }) + + addresses = addresses.concat( + appendAnnounceMultiaddrs.map(multiaddr => ({ + multiaddr, + verified: true, + type: 'announce', + expires: Date.now() + this.addressVerificationTTL, + lastVerified: Date.now() + })) + ) + } + + // add observed addresses + addresses = addresses.concat( + this.observed.getAll() + ) + + // add ip mapped addresses + addresses = addresses.concat( + this.ipMappings.getAll(addresses) + ) + + // add ip->domain mappings, must be done after IP mappings + addresses = addresses.concat( + this.dnsMappings.getAll(addresses) + ) + + return addresses + } + + addDNSMapping (domain: string, addresses: string[]): void { + this.dnsMappings.add(domain, addresses) + } + + removeDNSMapping (domain: string): void { + if (this.dnsMappings.remove(multiaddr(`/dns/${domain}`))) { + this._updatePeerStoreAddresses() + } + } + + addPublicAddressMapping (internalIp: string, internalPort: number, externalIp: string, externalPort: number = internalPort, protocol: 'tcp' | 'udp' = 'tcp'): void { + this.ipMappings.add(internalIp, internalPort, externalIp, externalPort, protocol) + + // remove duplicate observed addresses + this.observed.removePrefixed(`/ip${isIPv4(externalIp) ? 4 : 6}/${externalIp}/${protocol}/${externalPort}`) + } + + removePublicAddressMapping (internalIp: string, internalPort: number, externalIp: string, externalPort: number = internalPort, protocol: 'tcp' | 'udp' = 'tcp'): void { + if (this.ipMappings.remove(multiaddr(`/ip${isIPv4(externalIp) ? 4 : 6}/${externalIp}/${protocol}/${externalPort}`))) { + this._updatePeerStoreAddresses() + } + } + + /** + * Where an external service (router, gateway, etc) is forwarding traffic to + * us, attempt to add an IP mapping for the external address - this will + * include the observed mapping in the address list where we also have a DNS + * mapping for the external IP. + * + * Returns true if we added a new mapping + */ + private maybeUpgradeToIPMapping (ma: Multiaddr): boolean { + // this address is already mapped + if (this.ipMappings.has(ma)) { + return false + } + + const maOptions = ma.toOptions() + + // only public IPv4 addresses + if (maOptions.family === 6 || maOptions.host === '127.0.0.1' || isPrivateIp(maOptions.host) === true) { + return false + } + + const listeners = this.components.transportManager.getListeners() + + const transportMatchers: Array<(ma: Multiaddr) => boolean> = [ + (ma: Multiaddr) => WebSockets.exactMatch(ma) || WebSocketsSecure.exactMatch(ma), + (ma: Multiaddr) => TCP.exactMatch(ma), + (ma: Multiaddr) => QUIC_V1.exactMatch(ma) + ] + + for (const matcher of transportMatchers) { + // is the incoming address the same type as the matcher + if (!matcher(ma)) { + continue + } + + // get the listeners for this transport + const transportListeners = listeners.filter(listener => { + return listener.getAddrs().filter(ma => { + // only IPv4 addresses of the matcher type + return ma.toOptions().family === 4 && matcher(ma) + }).length > 0 + }) + + // because the NAT mapping could be forwarding different external ports to + // internal ones, we can only be sure enough to add a mapping if there is + // a single listener + if (transportListeners.length !== 1) { + continue + } + + // we have one listener which listens on one port so whatever the external + // NAT port mapping is, it should be for this listener + const linkLocalAddr = transportListeners[0].getAddrs().filter(ma => { + return ma.toOptions().host !== '127.0.0.1' + }).pop() + + if (linkLocalAddr == null) { + continue + } + + const linkLocalOptions = linkLocalAddr.toOptions() + + // upgrade observed address to IP mapping + this.observed.remove(ma) + this.ipMappings.add( + linkLocalOptions.host, + linkLocalOptions.port, + maOptions.host, + maOptions.port, + maOptions.transport + ) + + return true + } + + return false + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/ip-mappings.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/ip-mappings.ts new file mode 100644 index 000000000..e880d2e6f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/ip-mappings.ts @@ -0,0 +1,194 @@ +import { isIPv4 } from '@chainsafe/is-ip' +import { trackedMap } from '@libp2p/utils' +import { multiaddr, protocols } from '@multiformats/multiaddr' +import type { AddressManagerComponents, AddressManagerInit } from './index.js' +import type { Logger } from '@libp2p/interface' +import type { NodeAddress } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' + +export const defaultValues = { + maxObservedAddresses: 10 +} + +interface PublicAddressMapping { + internalIp: string + internalPort: number + externalIp: string + externalPort: number + externalFamily: 4 | 6 + protocol: 'tcp' | 'udp' + verified: boolean + expires: number + lastVerified?: number +} + +const CODEC_IP4 = 0x04 +const CODEC_IP6 = 0x29 +const CODEC_TCP = 0x06 +const CODEC_UDP = 0x0111 + +export class IPMappings { + private readonly log: Logger + private readonly mappings: Map + + constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) { + this.log = components.logger.forComponent('libp2p:address-manager:ip-mappings') + this.mappings = trackedMap({ + name: 'libp2p_address_manager_ip_mappings', + metrics: components.metrics + }) + } + + has (ma: Multiaddr): boolean { + const tuples = ma.stringTuples() + + for (const mappings of this.mappings.values()) { + for (const mapping of mappings) { + if (mapping.externalIp === tuples[0][1]) { + return true + } + } + } + + return false + } + + add (internalIp: string, internalPort: number, externalIp: string, externalPort: number = internalPort, protocol: 'tcp' | 'udp' = 'tcp'): void { + const key = `${internalIp}-${internalPort}-${protocol}` + const mappings = this.mappings.get(key) ?? [] + const mapping: PublicAddressMapping = { + internalIp, + internalPort, + externalIp, + externalPort, + externalFamily: isIPv4(externalIp) ? 4 : 6, + protocol, + verified: false, + expires: 0 + } + mappings.push(mapping) + + this.mappings.set(key, mappings) + } + + remove (ma: Multiaddr): boolean { + const tuples = ma.stringTuples() + const host = tuples[0][1] ?? '' + const protocol = tuples[1][0] === CODEC_TCP ? 'tcp' : 'udp' + const port = parseInt(tuples[1][1] ?? '0') + let wasConfident = false + + for (const [key, mappings] of this.mappings.entries()) { + for (let i = 0; i < mappings.length; i++) { + const mapping = mappings[i] + + if (mapping.externalIp === host && mapping.externalPort === port && mapping.protocol === protocol) { + this.log('removing %s:%s to %s:%s %s IP mapping', mapping.externalIp, mapping.externalPort, host, port, protocol) + + wasConfident = wasConfident || mapping.verified + mappings.splice(i, 1) + i-- + } + } + + if (mappings.length === 0) { + this.mappings.delete(key) + } + } + + return wasConfident + } + + getAll (addresses: NodeAddress[]): NodeAddress[] { + const ipMappedAddresses: NodeAddress[] = [] + + for (const { multiaddr: ma } of addresses) { + const tuples = ma.stringTuples() + let tuple: string | undefined + + // see if the internal host/port/protocol tuple has been mapped externally + if ((tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) && tuples[1][0] === CODEC_TCP) { + tuple = `${tuples[0][1]}-${tuples[1][1]}-tcp` + } else if ((tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) && tuples[1][0] === CODEC_UDP) { + tuple = `${tuples[0][1]}-${tuples[1][1]}-udp` + } + + if (tuple == null) { + continue + } + + const mappings = this.mappings.get(tuple) + + if (mappings == null) { + continue + } + + for (const mapping of mappings) { + tuples[0][0] = mapping.externalFamily === 4 ? CODEC_IP4 : CODEC_IP6 + tuples[0][1] = mapping.externalIp + tuples[1][1] = `${mapping.externalPort}` + + ipMappedAddresses.push({ + multiaddr: multiaddr(`/${ + tuples.map(tuple => { + return [ + protocols(tuple[0]).name, + tuple[1] + ].join('/') + }).join('/') + }`), + verified: mapping.verified, + type: 'ip-mapping', + expires: mapping.expires, + lastVerified: mapping.lastVerified + }) + } + } + + return ipMappedAddresses + } + + confirm (ma: Multiaddr, ttl: number): boolean { + const tuples = ma.stringTuples() + const host = tuples[0][1] + let startingConfidence = false + + for (const mappings of this.mappings.values()) { + for (const mapping of mappings) { + if (mapping.externalIp === host) { + this.log('marking %s to %s IP mapping as verified', mapping.internalIp, mapping.externalIp) + startingConfidence = mapping.verified + mapping.verified = true + mapping.expires = Date.now() + ttl + mapping.lastVerified = Date.now() + } + } + } + + return startingConfidence + } + + unconfirm (ma: Multiaddr, ttl: number): boolean { + const tuples = ma.stringTuples() + const host = tuples[0][1] ?? '' + const protocol = tuples[1][0] === CODEC_TCP ? 'tcp' : 'udp' + const port = parseInt(tuples[1][1] ?? '0') + let wasConfident = false + + for (const mappings of this.mappings.values()) { + for (let i = 0; i < mappings.length; i++) { + const mapping = mappings[i] + + if (mapping.externalIp === host && mapping.externalPort === port && mapping.protocol === protocol) { + this.log('removing verification of %s:%s to %s:%s %s IP mapping', mapping.externalIp, mapping.externalPort, host, port, protocol) + + wasConfident = wasConfident || mapping.verified + mapping.verified = false + mapping.expires = Date.now() + ttl + } + } + } + + return wasConfident + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/observed-addresses.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/observed-addresses.ts new file mode 100644 index 000000000..1e675b6f1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/observed-addresses.ts @@ -0,0 +1,97 @@ +import { isLinkLocal, isPrivate, trackedMap } from '@libp2p/utils' +import { multiaddr } from '@multiformats/multiaddr' +import type { AddressManagerComponents, AddressManagerInit } from './index.js' +import type { Logger } from '@libp2p/interface' +import type { NodeAddress } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' + +export const defaultValues = { + maxObservedAddresses: 10 +} + +interface ObservedAddressMetadata { + verified: boolean + expires: number + lastVerified?: number +} + +export class ObservedAddresses { + private readonly log: Logger + private readonly addresses: Map + private readonly maxObservedAddresses: number + + constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) { + this.log = components.logger.forComponent('libp2p:address-manager:observed-addresses') + this.addresses = trackedMap({ + name: 'libp2p_address_manager_observed_addresses', + metrics: components.metrics + }) + this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses + } + + has (ma: Multiaddr): boolean { + return this.addresses.has(ma.toString()) + } + + removePrefixed (prefix: string): void { + for (const key of this.addresses.keys()) { + if (key.toString().startsWith(prefix)) { + this.addresses.delete(key) + } + } + } + + add (ma: Multiaddr): void { + if (this.addresses.size === this.maxObservedAddresses) { + return + } + + if (isPrivate(ma) || isLinkLocal(ma)) { + return + } + + this.log('adding observed address %a', ma) + this.addresses.set(ma.toString(), { + verified: false, + expires: 0 + }) + } + + getAll (): NodeAddress[] { + return Array.from(this.addresses) + .map(([ma, metadata]) => ({ + multiaddr: multiaddr(ma), + verified: metadata.verified, + type: 'observed', + expires: metadata.expires, + lastVerified: metadata.lastVerified + })) + } + + remove (ma: Multiaddr): boolean { + const startingConfidence = this.addresses.get(ma.toString())?.verified ?? false + + this.log('removing observed address %a', ma) + this.addresses.delete(ma.toString()) + + return startingConfidence + } + + confirm (ma: Multiaddr, ttl: number): boolean { + const addrString = ma.toString() + const metadata = this.addresses.get(addrString) ?? { + verified: false, + expires: Date.now() + ttl, + lastVerified: Date.now() + } + const startingConfidence = metadata.verified + metadata.verified = true + metadata.expires = Date.now() + ttl + metadata.lastVerified = Date.now() + + this.log('marking observed address %a as verified', addrString) + this.addresses.set(addrString, metadata) + + return startingConfidence + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/transport-addresses.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/transport-addresses.ts new file mode 100644 index 000000000..97ab63468 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/address-manager/transport-addresses.ts @@ -0,0 +1,124 @@ +import { isNetworkAddress, isPrivate, trackedMap } from '@libp2p/utils' +import type { AddressManagerComponents, AddressManagerInit } from './index.js' +import type { Logger } from '@libp2p/interface' +import type { NodeAddress } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' + +export const defaultValues = { + maxObservedAddresses: 10 +} + +interface TransportAddressMetadata { + verified: boolean + expires: number + lastVerified?: number +} + +export class TransportAddresses { + private readonly log: Logger + private readonly addresses: Map + private readonly maxObservedAddresses: number + + constructor (components: AddressManagerComponents, init: AddressManagerInit = {}) { + this.log = components.logger.forComponent('libp2p:address-manager:observed-addresses') + this.addresses = trackedMap({ + name: 'libp2p_address_manager_transport_addresses', + metrics: components.metrics + }) + this.maxObservedAddresses = init.maxObservedAddresses ?? defaultValues.maxObservedAddresses + } + + get (multiaddr: Multiaddr, ttl: number): NodeAddress { + if (isPrivate(multiaddr)) { + return { + multiaddr, + verified: true, + type: 'transport', + expires: Date.now() + ttl, + lastVerified: Date.now() + } + } + + const key = this.toKey(multiaddr) + let metadata = this.addresses.get(key) + + if (metadata == null) { + metadata = { + verified: !isNetworkAddress(multiaddr), + expires: 0 + } + + this.addresses.set(key, metadata) + } + + return { + multiaddr, + verified: metadata.verified, + type: 'transport', + expires: metadata.expires, + lastVerified: metadata.lastVerified + } + } + + has (ma: Multiaddr): boolean { + const key = this.toKey(ma) + return this.addresses.has(key) + } + + remove (ma: Multiaddr): boolean { + const key = this.toKey(ma) + const startingConfidence = this.addresses.get(key)?.verified ?? false + + this.log('removing observed address %a', ma) + this.addresses.delete(key) + + return startingConfidence + } + + confirm (ma: Multiaddr, ttl: number): boolean { + const key = this.toKey(ma) + const metadata = this.addresses.get(key) ?? { + verified: false, + expires: 0, + lastVerified: 0 + } + + const startingConfidence = metadata.verified + + metadata.verified = true + metadata.expires = Date.now() + ttl + metadata.lastVerified = Date.now() + + this.addresses.set(key, metadata) + + return startingConfidence + } + + unconfirm (ma: Multiaddr, ttl: number): boolean { + const key = this.toKey(ma) + const metadata = this.addresses.get(key) ?? { + verified: false, + expires: 0 + } + + const startingConfidence = metadata.verified + + metadata.verified = false + metadata.expires = Date.now() + ttl + + this.addresses.set(key, metadata) + + return startingConfidence + } + + private toKey (ma: Multiaddr): string { + if (isNetworkAddress(ma)) { + // only works for dns/ip based addresses + const options = ma.toOptions() + + return `${options.host}-${options.port}-${options.transport}` + } + + return ma.toString() + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/components.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/components.ts new file mode 100644 index 000000000..7dd61e148 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/components.ts @@ -0,0 +1,199 @@ +import { serviceCapabilities, serviceDependencies, isStartable } from '@libp2p/interface' +import { defaultLogger } from '@libp2p/logger' +import { MissingServiceError, UnmetServiceDependenciesError } from './errors.js' +import type { Startable, Libp2pEvents, ComponentLogger, NodeInfo, ConnectionProtector, ConnectionGater, ContentRouting, Metrics, PeerId, PeerRouting, PeerStore, PrivateKey, Upgrader } from '@libp2p/interface' +import type { AddressManager, ConnectionManager, RandomWalk, Registrar, TransportManager } from '@libp2p/interface-internal' +import type { DNS } from '@multiformats/dns' +import type { Datastore } from 'interface-datastore' +import type { TypedEventTarget } from 'main-event' + +export interface Components extends Record, Startable { + peerId: PeerId + privateKey: PrivateKey + nodeInfo: NodeInfo + logger: ComponentLogger + events: TypedEventTarget + addressManager: AddressManager + peerStore: PeerStore + upgrader: Upgrader + randomWalk: RandomWalk + registrar: Registrar + connectionManager: ConnectionManager + transportManager: TransportManager + connectionGater: ConnectionGater + contentRouting: ContentRouting + peerRouting: PeerRouting + datastore: Datastore + connectionProtector?: ConnectionProtector + metrics?: Metrics + dns?: DNS +} + +export interface ComponentsInit { + peerId?: PeerId + privateKey?: PrivateKey + nodeInfo?: NodeInfo + logger?: ComponentLogger + events?: TypedEventTarget + addressManager?: AddressManager + peerStore?: PeerStore + upgrader?: Upgrader + randomWalk?: RandomWalk + metrics?: Metrics + registrar?: Registrar + connectionManager?: ConnectionManager + transportManager?: TransportManager + connectionGater?: ConnectionGater + contentRouting?: ContentRouting + peerRouting?: PeerRouting + datastore?: Datastore + connectionProtector?: ConnectionProtector + dns?: DNS +} + +class DefaultComponents implements Startable { + public components: Record = {} + private _started = false + + constructor (init: ComponentsInit = {}) { + this.components = {} + + for (const [key, value] of Object.entries(init)) { + this.components[key] = value + } + + if (this.components.logger == null) { + this.components.logger = defaultLogger() + } + } + + isStarted (): boolean { + return this._started + } + + private async _invokeStartableMethod (methodName: 'beforeStart' | 'start' | 'afterStart' | 'beforeStop' | 'stop' | 'afterStop'): Promise { + await Promise.all( + Object.values(this.components) + .filter(obj => isStartable(obj)) + .map(async (startable: Startable) => { + await startable[methodName]?.() + }) + ) + } + + async beforeStart (): Promise { + await this._invokeStartableMethod('beforeStart') + } + + async start (): Promise { + await this._invokeStartableMethod('start') + this._started = true + } + + async afterStart (): Promise { + await this._invokeStartableMethod('afterStart') + } + + async beforeStop (): Promise { + await this._invokeStartableMethod('beforeStop') + } + + async stop (): Promise { + await this._invokeStartableMethod('stop') + this._started = false + } + + async afterStop (): Promise { + await this._invokeStartableMethod('afterStop') + } +} + +const OPTIONAL_SERVICES = [ + 'metrics', + 'connectionProtector', + 'dns' +] + +const NON_SERVICE_PROPERTIES = [ + 'components', + 'isStarted', + 'beforeStart', + 'start', + 'afterStart', + 'beforeStop', + 'stop', + 'afterStop', + 'then', + '_invokeStartableMethod' +] + +export function defaultComponents (init: ComponentsInit = {}): Components { + const components = new DefaultComponents(init) + + const proxy = new Proxy(components, { + get (target, prop, receiver) { + if (typeof prop === 'string' && !NON_SERVICE_PROPERTIES.includes(prop)) { + const service = components.components[prop] + + if (service == null && !OPTIONAL_SERVICES.includes(prop)) { + throw new MissingServiceError(`${prop} not set`) + } + + return service + } + + return Reflect.get(target, prop, receiver) + }, + + set (target, prop, value) { + if (typeof prop === 'string') { + components.components[prop] = value + } else { + Reflect.set(target, prop, value) + } + + return true + } + }) + + // @ts-expect-error component keys are proxied + return proxy +} + +export function checkServiceDependencies (components: Components): void { + const serviceCapabilities: Record = {} + + for (const service of Object.values(components.components)) { + for (const capability of getServiceCapabilities(service)) { + serviceCapabilities[capability] = true + } + } + + for (const service of Object.values(components.components)) { + for (const capability of getServiceDependencies(service)) { + if (serviceCapabilities[capability] !== true) { + throw new UnmetServiceDependenciesError(`Service "${getServiceName(service)}" required capability "${capability}" but it was not provided by any component, you may need to add additional configuration when creating your node.`) + } + } + } +} + +function getServiceCapabilities (service: any): string[] { + if (Array.isArray(service?.[serviceCapabilities])) { + return service[serviceCapabilities] + } + + return [] +} + +function getServiceDependencies (service: any): string[] { + if (Array.isArray(service?.[serviceDependencies])) { + return service[serviceDependencies] + } + + return [] +} + +function getServiceName (service: any): string { + return service?.[Symbol.toStringTag] ?? service?.toString() ?? 'unknown' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config.ts new file mode 100644 index 000000000..966d853d7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config.ts @@ -0,0 +1,33 @@ +import { FaultTolerance, InvalidParametersError } from '@libp2p/interface' +import { mergeOptions } from '@libp2p/utils' +import { dnsaddrResolver } from './connection-manager/resolvers/dnsaddr.ts' +import type { Libp2pInit } from './index.js' +import type { ServiceMap } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +const DefaultConfig: Libp2pInit = { + addresses: { + listen: [], + announce: [], + noAnnounce: [], + announceFilter: (multiaddrs: Multiaddr[]) => multiaddrs + }, + connectionManager: { + resolvers: { + dnsaddr: dnsaddrResolver + } + }, + transportManager: { + faultTolerance: FaultTolerance.FATAL_ALL + } +} + +export async function validateConfig > (opts: Libp2pInit): Promise> { + const resultingOptions: Libp2pInit = mergeOptions(DefaultConfig, opts) + + if (resultingOptions.connectionProtector === null && globalThis.process?.env?.LIBP2P_FORCE_PNET != null) { + throw new InvalidParametersError('Private network is enforced, but no protector was provided') + } + + return resultingOptions +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config/connection-gater.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config/connection-gater.browser.ts new file mode 100644 index 000000000..8a3eae4d3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config/connection-gater.browser.ts @@ -0,0 +1,45 @@ +import { isPrivateIp } from '@libp2p/utils' +import { WebSockets } from '@multiformats/multiaddr-matcher' +import type { ConnectionGater } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +const CODEC_IP4 = 0x04 +const CODEC_IP6 = 0x29 + +/** + * Returns a connection gater that disallows dialling private addresses or + * insecure websockets by default. + * + * Browsers are severely limited in their resource usage so don't waste time + * trying to dial undialable addresses, and they also print verbose error + * messages when making connections over insecure transports which causes + * confusion. + */ +export function connectionGater (gater: ConnectionGater = {}): ConnectionGater { + return { + denyDialPeer: async () => false, + denyDialMultiaddr: async (multiaddr: Multiaddr) => { + // do not connect to insecure websockets by default + if (WebSockets.matches(multiaddr)) { + return false + } + + const tuples = multiaddr.stringTuples() + + // do not connect to private addresses by default + if (tuples[0][0] === CODEC_IP4 || tuples[0][0] === CODEC_IP6) { + return Boolean(isPrivateIp(`${tuples[0][1]}`)) + } + + return false + }, + denyInboundConnection: async () => false, + denyOutboundConnection: async () => false, + denyInboundEncryptedConnection: async () => false, + denyOutboundEncryptedConnection: async () => false, + denyInboundUpgradedConnection: async () => false, + denyOutboundUpgradedConnection: async () => false, + filterMultiaddrForPeer: async () => true, + ...gater + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config/connection-gater.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config/connection-gater.ts new file mode 100644 index 000000000..7739c71e9 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/config/connection-gater.ts @@ -0,0 +1,19 @@ +import type { ConnectionGater } from '@libp2p/interface' + +/** + * Returns a default connection gater implementation that allows everything + */ +export function connectionGater (gater: ConnectionGater = {}): ConnectionGater { + return { + denyDialPeer: async () => false, + denyDialMultiaddr: async () => false, + denyInboundConnection: async () => false, + denyOutboundConnection: async () => false, + denyInboundEncryptedConnection: async () => false, + denyOutboundEncryptedConnection: async () => false, + denyInboundUpgradedConnection: async () => false, + denyOutboundUpgradedConnection: async () => false, + filterMultiaddrForPeer: async () => true, + ...gater + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/address-sorter.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/address-sorter.ts new file mode 100644 index 000000000..0ff7c83d0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/address-sorter.ts @@ -0,0 +1,155 @@ +import { isLoopback, isPrivate } from '@libp2p/utils' +import { Circuit, WebSockets, WebSocketsSecure, WebRTC, WebRTCDirect, WebTransport, TCP } from '@multiformats/multiaddr-matcher' +import type { Address } from '@libp2p/interface' + +/** + * Sorts addresses by order of reliability, where they have presented the fewest + * problems: + * + * TCP -> WebSockets/Secure -> WebRTC -> WebRTCDirect -> WebTransport + */ +// eslint-disable-next-line complexity +export function reliableTransportsFirst (a: Address, b: Address): -1 | 0 | 1 { + const isATcp = TCP.exactMatch(a.multiaddr) + const isBTcp = TCP.exactMatch(b.multiaddr) + + if (isATcp && !isBTcp) { + return -1 + } + + if (!isATcp && isBTcp) { + return 1 + } + + const isAWebSocketSecure = WebSocketsSecure.exactMatch(a.multiaddr) + const isBWebSocketSecure = WebSocketsSecure.exactMatch(b.multiaddr) + + if (isAWebSocketSecure && !isBWebSocketSecure) { + return -1 + } + + if (!isAWebSocketSecure && isBWebSocketSecure) { + return 1 + } + + const isAWebSocket = WebSockets.exactMatch(a.multiaddr) + const isBWebSocket = WebSockets.exactMatch(b.multiaddr) + + if (isAWebSocket && !isBWebSocket) { + return -1 + } + + if (!isAWebSocket && isBWebSocket) { + return 1 + } + + const isAWebRTC = WebRTC.exactMatch(a.multiaddr) + const isBWebRTC = WebRTC.exactMatch(b.multiaddr) + + if (isAWebRTC && !isBWebRTC) { + return -1 + } + + if (!isAWebRTC && isBWebRTC) { + return 1 + } + + const isAWebRTCDirect = WebRTCDirect.exactMatch(a.multiaddr) + const isBWebRTCDirect = WebRTCDirect.exactMatch(b.multiaddr) + + if (isAWebRTCDirect && !isBWebRTCDirect) { + return -1 + } + + if (!isAWebRTCDirect && isBWebRTCDirect) { + return 1 + } + + const isAWebTransport = WebTransport.exactMatch(a.multiaddr) + const isBWebTransport = WebTransport.exactMatch(b.multiaddr) + + if (isAWebTransport && !isBWebTransport) { + return -1 + } + + if (!isAWebTransport && isBWebTransport) { + return 1 + } + + // ... everything else + return 0 +} + +/** + * Compare function for array.sort() that moves loopback addresses to the end + * of the array. + */ +export function loopbackAddressLast (a: Address, b: Address): -1 | 0 | 1 { + const isALoopback = isLoopback(a.multiaddr) + const isBLoopback = isLoopback(b.multiaddr) + + if (isALoopback && !isBLoopback) { + return 1 + } else if (!isALoopback && isBLoopback) { + return -1 + } + + return 0 +} + +/** + * Compare function for array.sort() that moves public addresses to the start + * of the array. + */ +export function publicAddressesFirst (a: Address, b: Address): -1 | 0 | 1 { + const isAPrivate = isPrivate(a.multiaddr) + const isBPrivate = isPrivate(b.multiaddr) + + if (isAPrivate && !isBPrivate) { + return 1 + } else if (!isAPrivate && isBPrivate) { + return -1 + } + + return 0 +} + +/** + * Compare function for array.sort() that moves certified addresses to the start + * of the array. + */ +export function certifiedAddressesFirst (a: Address, b: Address): -1 | 0 | 1 { + if (a.isCertified && !b.isCertified) { + return -1 + } else if (!a.isCertified && b.isCertified) { + return 1 + } + + return 0 +} + +/** + * Compare function for array.sort() that moves circuit relay addresses to the + * end of the array. + */ +export function circuitRelayAddressesLast (a: Address, b: Address): -1 | 0 | 1 { + const isACircuit = Circuit.exactMatch(a.multiaddr) + const isBCircuit = Circuit.exactMatch(b.multiaddr) + + if (isACircuit && !isBCircuit) { + return 1 + } else if (!isACircuit && isBCircuit) { + return -1 + } + + return 0 +} + +export function defaultAddressSorter (addresses: Address[]): Address[] { + return addresses + .sort(reliableTransportsFirst) + .sort(certifiedAddressesFirst) + .sort(circuitRelayAddressesLast) + .sort(publicAddressesFirst) + .sort(loopbackAddressLast) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/connection-pruner.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/connection-pruner.ts new file mode 100644 index 000000000..6e0031777 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/connection-pruner.ts @@ -0,0 +1,188 @@ +import { PeerMap } from '@libp2p/peer-collections' +import { multiaddrToIpNet, safelyCloseConnectionIfUnused } from './utils.js' +import type { IpNet } from '@chainsafe/netmask' +import type { Libp2pEvents, Logger, ComponentLogger, PeerStore, Connection } from '@libp2p/interface' +import type { ConnectionManager } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { TypedEventTarget } from 'main-event' + +interface ConnectionPrunerInit { + allow?: Multiaddr[] +} + +interface ConnectionPrunerComponents { + connectionManager: ConnectionManager + peerStore: PeerStore + events: TypedEventTarget + logger: ComponentLogger +} + +/** + * If we go over the max connections limit, choose some connections to close + */ +export class ConnectionPruner { + private readonly connectionManager: ConnectionManager + private readonly peerStore: PeerStore + private readonly allow: IpNet[] + private readonly events: TypedEventTarget + private readonly log: Logger + + constructor (components: ConnectionPrunerComponents, init: ConnectionPrunerInit = {}) { + this.allow = (init.allow ?? []).map(ma => multiaddrToIpNet(ma)) + this.connectionManager = components.connectionManager + this.peerStore = components.peerStore + this.events = components.events + this.log = components.logger.forComponent('libp2p:connection-manager:connection-pruner') + this.maybePruneConnections = this.maybePruneConnections.bind(this) + } + + start (): void { + this.events.addEventListener('connection:open', this.maybePruneConnections) + } + + stop (): void { + this.events.removeEventListener('connection:open', this.maybePruneConnections) + } + + maybePruneConnections (): void { + this._maybePruneConnections() + .catch(err => { + this.log.error('error while pruning connections %e', err) + }) + } + + /** + * If we have more connections than our maximum, select some excess connections + * to prune based on peer value + */ + private async _maybePruneConnections (): Promise { + const connections = this.connectionManager.getConnections() + const numConnections = connections.length + const maxConnections = this.connectionManager.getMaxConnections() + + this.log('checking max connections limit %d/%d', numConnections, maxConnections) + + if (numConnections <= maxConnections) { + return + } + + const peerValues = new PeerMap() + + // work out peer values + for (const connection of connections) { + const remotePeer = connection.remotePeer + + if (peerValues.has(remotePeer)) { + continue + } + + peerValues.set(remotePeer, 0) + + try { + const peer = await this.peerStore.get(remotePeer) + + // sum all tag values + peerValues.set(remotePeer, [...peer.tags.values()].reduce((acc, curr) => { + return acc + curr.value + }, 0)) + } catch (err: any) { + if (err.name !== 'NotFoundError') { + this.log.error('error loading peer tags', err) + } + } + } + + const sortedConnections = this.sortConnections(connections, peerValues) + + // close some connections + const toPrune = Math.max(numConnections - maxConnections, 0) + const toClose = [] + + for (const connection of sortedConnections) { + this.log('too many connections open - closing a connection to %p', connection.remotePeer) + // check allow list + const connectionInAllowList = this.allow.some((ipNet) => { + return ipNet.contains(connection.remoteAddr.nodeAddress().address) + }) + + // Connections in the allow list should be excluded from pruning + if (!connectionInAllowList) { + toClose.push(connection) + } + + if (toClose.length === toPrune) { + break + } + } + + // close connections + await Promise.all( + toClose.map(async connection => { + await safelyCloseConnectionIfUnused(connection, { + signal: AbortSignal.timeout(1000) + }) + }) + ) + + // despatch prune event + this.events.safeDispatchEvent('connection:prune', { detail: toClose }) + } + + sortConnections (connections: Connection[], peerValues: PeerMap): Connection[] { + return connections + // sort by connection age, newest to oldest + .sort((a, b) => { + const connectionALifespan = a.timeline.open + const connectionBLifespan = b.timeline.open + + if (connectionALifespan < connectionBLifespan) { + return 1 + } + + if (connectionALifespan > connectionBLifespan) { + return -1 + } + + return 0 + }) + // sort by direction, incoming first then outgoing + .sort((a, b) => { + if (a.direction === 'outbound' && b.direction === 'inbound') { + return 1 + } + + if (a.direction === 'inbound' && b.direction === 'outbound') { + return -1 + } + + return 0 + }) + // sort by number of streams, lowest to highest + .sort((a, b) => { + if (a.streams.length > b.streams.length) { + return 1 + } + + if (a.streams.length < b.streams.length) { + return -1 + } + + return 0 + }) + // sort by tag value, lowest to highest + .sort((a, b) => { + const peerAValue = peerValues.get(a.remotePeer) ?? 0 + const peerBValue = peerValues.get(b.remotePeer) ?? 0 + + if (peerAValue > peerBValue) { + return 1 + } + + if (peerAValue < peerBValue) { + return -1 + } + + return 0 + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.browser.ts new file mode 100644 index 000000000..cdafdbcdb --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.browser.ts @@ -0,0 +1,11 @@ +export * from './constants.defaults.js' + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxConnections + */ +export const MAX_CONNECTIONS = 100 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDials + */ +export const MAX_PARALLEL_DIALS = 50 diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.defaults.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.defaults.ts new file mode 100644 index 000000000..c82ecf7e7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.defaults.ts @@ -0,0 +1,61 @@ +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#dialTimeout + */ +export const DIAL_TIMEOUT = 10_000 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#inboundUpgradeTimeout + */ +export const INBOUND_UPGRADE_TIMEOUT = 10_000 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#protocolNegotiationTimeout + */ +export const PROTOCOL_NEGOTIATION_TIMEOUT = 10_000 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxPeerAddrsToDial + */ +export const MAX_PEER_ADDRS_TO_DIAL = 25 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#inboundConnectionThreshold + */ +export const INBOUND_CONNECTION_THRESHOLD = 5 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxIncomingPendingConnections + */ +export const MAX_INCOMING_PENDING_CONNECTIONS = 10 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelReconnects + */ +export const MAX_PARALLEL_RECONNECTS = 5 + +/** + * Store as part of the peer store metadata for a given peer, the value for this + * key is a timestamp of the last time a dial attempt failed with the timestamp + * stored as a string. + * + * Used to insure we do not endlessly try to auto dial peers we have recently + * failed to dial. + */ +export const LAST_DIAL_FAILURE_KEY = 'last-dial-failure' + +/** + * Store as part of the peer store metadata for a given peer, the value for this + * key is a timestamp of the last time a dial attempt succeeded with the + * timestamp stored as a string. + */ +export const LAST_DIAL_SUCCESS_KEY = 'last-dial-success' + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxDialQueueLength + */ +export const MAX_DIAL_QUEUE_LENGTH = 500 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxRecursiveDepth + */ +export const MAX_RECURSIVE_DEPTH = 32 diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.ts new file mode 100644 index 000000000..422074f57 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/constants.ts @@ -0,0 +1,11 @@ +export * from './constants.defaults.js' + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxConnections + */ +export const MAX_CONNECTIONS = 300 + +/** + * @see https://libp2p.github.io/js-libp2p/interfaces/index._internal_.ConnectionManagerConfig.html#maxParallelDials + */ +export const MAX_PARALLEL_DIALS = 100 diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/dial-queue.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/dial-queue.ts new file mode 100644 index 000000000..c75a0b428 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/dial-queue.ts @@ -0,0 +1,539 @@ +/* eslint-disable max-depth */ +import { TimeoutError, DialError, AbortError } from '@libp2p/interface' +import { PeerMap } from '@libp2p/peer-collections' +import { PriorityQueue } from '@libp2p/utils' +import { multiaddr } from '@multiformats/multiaddr' +import { Circuit } from '@multiformats/multiaddr-matcher' +import { anySignal } from 'any-signal' +import { setMaxListeners } from 'main-event' +import { CustomProgressEvent } from 'progress-events' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { DialDeniedError, NoValidAddressesError } from '../errors.js' +import { getPeerAddress } from '../get-peer.js' +import { defaultAddressSorter } from './address-sorter.js' +import { + DIAL_TIMEOUT, + MAX_PARALLEL_DIALS, + MAX_PEER_ADDRS_TO_DIAL, + LAST_DIAL_FAILURE_KEY, + MAX_DIAL_QUEUE_LENGTH, + LAST_DIAL_SUCCESS_KEY +} from './constants.js' +import { resolveMultiaddr, dnsaddrResolver } from './resolvers/index.js' +import { DEFAULT_DIAL_PRIORITY } from './index.js' +import type { AddressSorter, ComponentLogger, Logger, Connection, ConnectionGater, Metrics, PeerId, Address, PeerStore, PeerRouting, IsDialableOptions, OpenConnectionProgressEvents, MultiaddrResolver } from '@libp2p/interface' +import type { OpenConnectionOptions, TransportManager } from '@libp2p/interface-internal' +import type { PriorityQueueJobOptions } from '@libp2p/utils' +import type { DNS } from '@multiformats/dns' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { ProgressOptions } from 'progress-events' + +export interface PendingDialTarget { + resolve(value: any): void + reject(err: Error): void +} + +interface DialQueueJobOptions extends PriorityQueueJobOptions, ProgressOptions { + peerId?: PeerId + multiaddrs: Set +} + +interface DialerInit { + addressSorter?: AddressSorter + maxParallelDials?: number + maxDialQueueLength?: number + maxPeerAddrsToDial?: number + dialTimeout?: number + resolvers?: Record + connections?: PeerMap +} + +const defaultOptions = { + maxParallelDials: MAX_PARALLEL_DIALS, + maxDialQueueLength: MAX_DIAL_QUEUE_LENGTH, + maxPeerAddrsToDial: MAX_PEER_ADDRS_TO_DIAL, + dialTimeout: DIAL_TIMEOUT, + resolvers: { + dnsaddr: dnsaddrResolver + } +} + +interface DialQueueComponents { + peerId: PeerId + metrics?: Metrics + peerStore: PeerStore + peerRouting: PeerRouting + transportManager: TransportManager + connectionGater: ConnectionGater + logger: ComponentLogger + dns?: DNS +} + +export class DialQueue { + public queue: PriorityQueue + private readonly components: DialQueueComponents + private readonly addressSorter?: AddressSorter + private readonly maxPeerAddrsToDial: number + private readonly maxDialQueueLength: number + private readonly dialTimeout: number + private shutDownController: AbortController + private readonly connections: PeerMap + private readonly log: Logger + private readonly resolvers: Record + + constructor (components: DialQueueComponents, init: DialerInit = {}) { + this.addressSorter = init.addressSorter + this.maxPeerAddrsToDial = init.maxPeerAddrsToDial ?? defaultOptions.maxPeerAddrsToDial + this.maxDialQueueLength = init.maxDialQueueLength ?? defaultOptions.maxDialQueueLength + this.dialTimeout = init.dialTimeout ?? defaultOptions.dialTimeout + this.connections = init.connections ?? new PeerMap() + this.log = components.logger.forComponent('libp2p:connection-manager:dial-queue') + this.components = components + this.resolvers = init.resolvers ?? defaultOptions.resolvers + + this.shutDownController = new AbortController() + setMaxListeners(Infinity, this.shutDownController.signal) + + // controls dial concurrency + this.queue = new PriorityQueue({ + concurrency: init.maxParallelDials ?? defaultOptions.maxParallelDials, + metricName: 'libp2p_dial_queue', + metrics: components.metrics + }) + // a started job errored + this.queue.addEventListener('failure', (event) => { + if (event.detail?.error.name !== AbortError.name) { + this.log.error('error in dial queue - %e', event.detail.error) + } + }) + } + + start (): void { + this.shutDownController = new AbortController() + setMaxListeners(Infinity, this.shutDownController.signal) + } + + /** + * Clears any pending dials + */ + stop (): void { + this.shutDownController.abort() + this.queue.abort() + } + + /** + * Connects to a given peer, multiaddr or list of multiaddrs. + * + * If a peer is passed, all known multiaddrs will be tried. If a multiaddr or + * multiaddrs are passed only those will be dialled. + * + * Where a list of multiaddrs is passed, if any contain a peer id then all + * multiaddrs in the list must contain the same peer id. + * + * The dial to the first address that is successfully able to upgrade a + * connection will be used, all other dials will be aborted when that happens. + */ + async dial (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: OpenConnectionOptions = {}): Promise { + const { peerId, multiaddrs } = getPeerAddress(peerIdOrMultiaddr) + + // make sure we don't have an existing non-limited connection to any of the + // addresses we are about to dial + const existingConnection = Array.from(this.connections.values()).flat().find(conn => { + if (options.force === true) { + return false + } + + if (conn.limits != null) { + return false + } + + if (conn.remotePeer.equals(peerId)) { + return true + } + + return multiaddrs.find(addr => { + return addr.equals(conn.remoteAddr) + }) + }) + + if (existingConnection?.status === 'open') { + this.log('already connected to %a', existingConnection.remoteAddr) + options.onProgress?.(new CustomProgressEvent('dial-queue:already-connected')) + return existingConnection + } + + // ready to dial, all async work finished - make sure we don't have any + // pending dials in progress for this peer or set of multiaddrs + const existingDial = this.queue.queue.find(job => { + if (peerId?.equals(job.options.peerId) === true) { + return true + } + + // does the dial contain any of the target multiaddrs? + const addresses = job.options.multiaddrs + + if (addresses == null) { + return false + } + + for (const multiaddr of multiaddrs) { + if (addresses.has(multiaddr.toString())) { + return true + } + } + + return false + }) + + if (existingDial != null) { + this.log('joining existing dial target for %p', peerId) + + // add all multiaddrs to the dial target + for (const multiaddr of multiaddrs) { + existingDial.options.multiaddrs.add(multiaddr.toString()) + } + + options.onProgress?.(new CustomProgressEvent('dial-queue:already-in-dial-queue')) + return existingDial.join(options) + } + + if (this.queue.size >= this.maxDialQueueLength) { + throw new DialError('Dial queue is full') + } + + this.log('creating dial target for %p', peerId, multiaddrs.map(ma => ma.toString())) + + options.onProgress?.(new CustomProgressEvent('dial-queue:add-to-dial-queue')) + return this.queue.add(async (options) => { + options.onProgress?.(new CustomProgressEvent('dial-queue:start-dial')) + // create abort conditions - need to do this before `calculateMultiaddrs` as + // we may be about to resolve a dns addr which can time out + const signal = anySignal([ + this.shutDownController.signal, + options.signal + ]) + setMaxListeners(Infinity, signal) + + try { + return await this.dialPeer(options, signal) + } finally { + // clean up abort signals/controllers + signal.clear() + } + }, { + peerId, + priority: options.priority ?? DEFAULT_DIAL_PRIORITY, + multiaddrs: new Set(multiaddrs.map(ma => ma.toString())), + signal: options.signal ?? AbortSignal.timeout(this.dialTimeout), + onProgress: options.onProgress + }) + } + + private async dialPeer (options: DialQueueJobOptions, signal: AbortSignal): Promise { + const peerId = options.peerId + const multiaddrs = options.multiaddrs + const failedMultiaddrs = new Set() + + // if we have no multiaddrs, only a peer id, set a flag so we will look the + // peer up in the peer routing to obtain multiaddrs + let forcePeerLookup = options.multiaddrs.size === 0 + + let dialed = 0 + let dialIteration = 0 + const errors: Error[] = [] + + this.log('starting dial to %p', peerId) + + // repeat this operation in case addresses are added to the dial while we + // resolve multiaddrs, etc + while (forcePeerLookup || multiaddrs.size > 0) { + dialIteration++ + + // only perform peer lookup once + forcePeerLookup = false + + // the addresses we will dial + const addrsToDial: Address[] = [] + + // copy the addresses into a new set + const addrs = new Set(options.multiaddrs) + + // empty the old set - subsequent dial attempts for the same peer id may + // add more addresses to try + multiaddrs.clear() + + this.log('calculating addrs to dial %p from %s', peerId, [...addrs]) + + // load addresses from address book, resolve and dnsaddrs, filter + // undialables, add peer IDs, etc + const calculatedAddrs = await this.calculateMultiaddrs(peerId, addrs, { + ...options, + signal + }) + + for (const addr of calculatedAddrs) { + // skip any addresses we have previously failed to dial + if (failedMultiaddrs.has(addr.multiaddr.toString())) { + this.log.trace('skipping previously failed multiaddr %a while dialing %p', addr.multiaddr, peerId) + continue + } + + addrsToDial.push(addr) + } + + this.log('%s dial to %p with %s', dialIteration === 1 ? 'starting' : 'continuing', peerId, addrsToDial.map(ma => ma.multiaddr.toString())) + + options?.onProgress?.(new CustomProgressEvent('dial-queue:calculated-addresses', addrsToDial)) + + for (const address of addrsToDial) { + if (dialed === this.maxPeerAddrsToDial) { + this.log('dialed maxPeerAddrsToDial (%d) addresses for %p, not trying any others', dialed, options.peerId) + + throw new DialError('Peer had more than maxPeerAddrsToDial') + } + + dialed++ + + try { + // try to dial the address + const conn = await this.components.transportManager.dial(address.multiaddr, { + ...options, + signal + }) + + this.log('dial to %a succeeded', address.multiaddr) + + // record the successful dial and the address + try { + await this.components.peerStore.merge(conn.remotePeer, { + multiaddrs: [ + conn.remoteAddr + ], + metadata: { + [LAST_DIAL_SUCCESS_KEY]: uint8ArrayFromString(Date.now().toString()) + } + }) + } catch (err: any) { + this.log.error('could not update last dial failure key for %p', peerId, err) + } + + // dial successful, return the connection + return conn + } catch (err: any) { + this.log.error('dial failed to %a', address.multiaddr, err) + + // ensure we don't dial it again in this attempt + failedMultiaddrs.add(address.multiaddr.toString()) + + if (peerId != null) { + // record the failed dial + try { + await this.components.peerStore.merge(peerId, { + metadata: { + [LAST_DIAL_FAILURE_KEY]: uint8ArrayFromString(Date.now().toString()) + } + }) + } catch (err: any) { + this.log.error('could not update last dial failure key for %p', peerId, err) + } + } + + // the user/dial timeout/shutdown controller signal aborted + if (signal.aborted) { + throw new TimeoutError(err.message) + } + + errors.push(err) + } + } + } + + if (errors.length === 1) { + throw errors[0] + } + + throw new AggregateError(errors, 'All multiaddr dials failed') + } + + // eslint-disable-next-line complexity + private async calculateMultiaddrs (peerId?: PeerId, multiaddrs: Set = new Set(), options: OpenConnectionOptions = {}): Promise { + const addrs: Address[] = [...multiaddrs].map(ma => ({ + multiaddr: multiaddr(ma), + isCertified: false + })) + + // if a peer id or multiaddr(s) with a peer id, make sure it isn't our peer id and that we are allowed to dial it + if (peerId != null) { + if (this.components.peerId.equals(peerId)) { + throw new DialError('Tried to dial self') + } + + if ((await this.components.connectionGater.denyDialPeer?.(peerId)) === true) { + throw new DialDeniedError('The dial request is blocked by gater.allowDialPeer') + } + + // if just a peer id was passed, load available multiaddrs for this peer + // from the peer store + if (addrs.length === 0) { + this.log('loading multiaddrs for %p', peerId) + try { + const peer = await this.components.peerStore.get(peerId) + addrs.push(...peer.addresses) + this.log('loaded multiaddrs for %p', peerId, addrs.map(({ multiaddr }) => multiaddr.toString())) + } catch (err: any) { + if (err.name !== 'NotFoundError') { + throw err + } + } + } + + // if we still don't have any addresses for this peer, or the only + // addresses we have are without any routing information (e.g. + // `/p2p/Qmfoo`), try a lookup using the peer routing + if (addrs.length === 0) { + this.log('looking up multiaddrs for %p in the peer routing', peerId) + + try { + const peerInfo = await this.components.peerRouting.findPeer(peerId, options) + + this.log('found multiaddrs for %p in the peer routing', peerId, addrs.map(({ multiaddr }) => multiaddr.toString())) + + addrs.push(...peerInfo.multiaddrs.map(multiaddr => ({ + multiaddr, + isCertified: false + }))) + } catch (err: any) { + if (err.name === 'NoPeerRoutersError') { + this.log('no peer routers configured', peerId) + } else { + this.log.error('looking up multiaddrs for %p in the peer routing failed - %e', peerId, err) + } + } + } + } + + // resolve addresses - this can result in a one-to-many translation when + // dnsaddrs are resolved + let resolvedAddresses = (await Promise.all( + addrs.map(async addr => { + const result = await resolveMultiaddr(addr.multiaddr, this.resolvers, { + dns: this.components.dns, + log: this.log, + ...options + }) + + if (result.length === 1 && result[0].equals(addr.multiaddr)) { + return addr + } + + return result.map(multiaddr => ({ + multiaddr, + isCertified: false + })) + }) + )) + .flat() + + // ensure the peer id is appended to the multiaddr + if (peerId != null) { + const peerIdMultiaddr = `/p2p/${peerId.toString()}` + resolvedAddresses = resolvedAddresses.map(addr => { + const lastComponent = addr.multiaddr.getComponents().pop() + + // append peer id to multiaddr if it is not already present + if (lastComponent?.name !== 'p2p') { + return { + multiaddr: addr.multiaddr.encapsulate(peerIdMultiaddr), + isCertified: addr.isCertified + } + } + + return addr + }) + } + + const filteredAddrs = resolvedAddresses.filter(addr => { + // filter out any multiaddrs that we do not have transports for + if (this.components.transportManager.dialTransportForMultiaddr(addr.multiaddr) == null) { + return false + } + + // if the resolved multiaddr has a PeerID but it's the wrong one, ignore it + // - this can happen with addresses like bootstrap.libp2p.io that resolve + // to multiple different peers + const addrPeerId = addr.multiaddr.getPeerId() + if (peerId != null && addrPeerId != null) { + return peerId.equals(addrPeerId) + } + + return true + }) + + // deduplicate addresses + const dedupedAddrs = new Map() + + for (const addr of filteredAddrs) { + const maStr = addr.multiaddr.toString() + const existing = dedupedAddrs.get(maStr) + + if (existing != null) { + existing.isCertified = existing.isCertified || addr.isCertified || false + continue + } + + dedupedAddrs.set(maStr, addr) + } + + const dedupedMultiaddrs = [...dedupedAddrs.values()] + + // make sure we actually have some addresses to dial + if (dedupedMultiaddrs.length === 0) { + throw new NoValidAddressesError('The dial request has no valid addresses') + } + + const gatedAddrs: Address[] = [] + + for (const addr of dedupedMultiaddrs) { + if (this.components.connectionGater.denyDialMultiaddr != null && await this.components.connectionGater.denyDialMultiaddr(addr.multiaddr)) { + continue + } + + gatedAddrs.push(addr) + } + + const sortedGatedAddrs = this.addressSorter == null ? defaultAddressSorter(gatedAddrs) : gatedAddrs.sort(this.addressSorter) + + // make sure we actually have some addresses to dial + if (sortedGatedAddrs.length === 0) { + throw new DialDeniedError('The connection gater denied all addresses in the dial request') + } + + this.log.trace('addresses for %p before filtering', peerId ?? 'unknown peer', resolvedAddresses.map(({ multiaddr }) => multiaddr.toString())) + this.log.trace('addresses for %p after filtering', peerId ?? 'unknown peer', sortedGatedAddrs.map(({ multiaddr }) => multiaddr.toString())) + + return sortedGatedAddrs + } + + async isDialable (multiaddr: Multiaddr | Multiaddr[], options: IsDialableOptions = {}): Promise { + if (!Array.isArray(multiaddr)) { + multiaddr = [multiaddr] + } + + try { + const addresses = await this.calculateMultiaddrs(undefined, new Set(multiaddr.map(ma => ma.toString())), options) + + if (options.runOnLimitedConnection === false) { + // return true if any resolved multiaddrs are not relay addresses + return addresses.find(addr => { + return !Circuit.matches(addr.multiaddr) + }) != null + } + + return true + } catch (err) { + this.log.trace('error calculating if multiaddr(s) were dialable', err) + } + + return false + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/index.ts new file mode 100644 index 000000000..7eeaa22c1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/index.ts @@ -0,0 +1,691 @@ +import { ConnectionClosedError, InvalidMultiaddrError, InvalidParametersError, InvalidPeerIdError, NotStartedError, start, stop } from '@libp2p/interface' +import { PeerMap } from '@libp2p/peer-collections' +import { RateLimiter } from '@libp2p/utils' +import { multiaddr } from '@multiformats/multiaddr' +import { CustomProgressEvent } from 'progress-events' +import { getPeerAddress } from '../get-peer.js' +import { ConnectionPruner } from './connection-pruner.js' +import { DIAL_TIMEOUT, INBOUND_CONNECTION_THRESHOLD, MAX_CONNECTIONS, MAX_DIAL_QUEUE_LENGTH, MAX_INCOMING_PENDING_CONNECTIONS, MAX_PARALLEL_DIALS, MAX_PEER_ADDRS_TO_DIAL } from './constants.js' +import { DialQueue } from './dial-queue.js' +import { ReconnectQueue } from './reconnect-queue.js' +import { dnsaddrResolver } from './resolvers/index.ts' +import { multiaddrToIpNet } from './utils.js' +import type { IpNet } from '@chainsafe/netmask' +import type { PendingDial, AddressSorter, Libp2pEvents, AbortOptions, ComponentLogger, Logger, Connection, MultiaddrConnection, ConnectionGater, Metrics, PeerId, PeerStore, Startable, PendingDialStatus, PeerRouting, IsDialableOptions, MultiaddrResolver } from '@libp2p/interface' +import type { ConnectionManager, OpenConnectionOptions, TransportManager } from '@libp2p/interface-internal' +import type { JobStatus } from '@libp2p/utils' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { TypedEventTarget } from 'main-event' + +export const DEFAULT_DIAL_PRIORITY = 50 + +export interface ConnectionManagerInit { + /** + * The maximum number of connections libp2p is willing to have before it + * starts pruning connections to reduce resource usage. + * + * @default 300/100 + */ + maxConnections?: number + + /** + * Sort the known addresses of a peer before trying to dial, By default public + * addresses will be dialled before private (e.g. loopback or LAN) addresses. + */ + addressSorter?: AddressSorter + + /** + * The maximum number of dials across all peers to execute in parallel. + * + * @default 100/50 + */ + maxParallelDials?: number + + /** + * The maximum size the dial queue is allowed to grow to. Promises returned + * when dialing peers after this limit is reached will not resolve until the + * queue size falls beneath this size. + * + * @default 500 + */ + maxDialQueueLength?: number + + /** + * Maximum number of addresses allowed for a given peer before giving up + * + * @default 25 + */ + maxPeerAddrsToDial?: number + + /** + * How long a dial attempt is allowed to take, including DNS resolution + * of the multiaddr, opening a socket and upgrading it to a Connection. + * + * @default 10_000 + */ + dialTimeout?: number + + /** + * When a new incoming connection is opened, the upgrade process (e.g. + * protect, encrypt, multiplex etc) must complete within this number of ms. + * + * @default 10_000 + */ + inboundUpgradeTimeout?: number + + /** + * When a new outbound connection is opened, the upgrade process (e.g. + * protect, encrypt, multiplex etc) must complete within this number of ms. + * + * Does not apply if an abort signal is passed to the `.dial` method. + * + * @deprecated This is handled by `dialTimeout` + */ + outboundUpgradeTimeout?: number + + /** + * Protocol negotiation must complete within this number of ms + * + * @default 2000 + * @deprecated use outboundStreamProtocolNegotiationTimeout or inboundStreamProtocolNegotiationTimeout instead + */ + protocolNegotiationTimeout?: number + + /** + * Outbound protocol negotiation must complete within this number of ms. + * + * Does not apply if an abort signal is passed to the `.dial` or + * `.dialProtocol` method of the `ConnectionManager` or the `openStream` + * method of the `Connection`. + * + * @default 10_000 + */ + outboundStreamProtocolNegotiationTimeout?: number + + /** + * Inbound protocol negotiation must complete within this number of ms + * + * @default 10_000 + */ + inboundStreamProtocolNegotiationTimeout?: number + + /** + * Multiaddr resolvers to use when dialling + */ + resolvers?: Record + + /** + * A list of multiaddrs that will always be allowed (except if they are in the + * deny list) to open connections to this node even if we've reached + * maxConnections + */ + allow?: string[] + + /** + * A list of multiaddrs that will never be allowed to open connections to + * this node under any circumstances + */ + deny?: string[] + + /** + * If more than this many connections are opened per second by a single + * host, reject subsequent connections. + * + * @default 5 + */ + inboundConnectionThreshold?: number + + /** + * The maximum number of parallel incoming connections allowed that have yet + * to complete the connection upgrade - e.g. choosing connection encryption, + * muxer, etc. + * + * @default 10 + */ + maxIncomingPendingConnections?: number + + /** + * When a peer tagged with `KEEP_ALIVE` disconnects, attempt to redial them + * this many times. + * + * @default 5 + */ + reconnectRetries?: number + + /** + * When a peer tagged with `KEEP_ALIVE` disconnects, wait this long between + * each retry. Note this will be multiplied by `reconnectFactor` to create an + * increasing retry backoff. + * + * @default 1000 + */ + reconnectRetryInterval?: number + + /** + * When a peer tagged with `KEEP_ALIVE` disconnects, apply this multiplication + * factor to the time interval between each retry. + * + * @default 2 + */ + reconnectBackoffFactor?: number + + /** + * When a peers tagged with `KEEP_ALIVE` disconnect, reconnect to this many at + * once. + * + * @default 5 + */ + maxParallelReconnects?: number +} + +const defaultOptions = { + maxConnections: MAX_CONNECTIONS, + inboundConnectionThreshold: INBOUND_CONNECTION_THRESHOLD, + maxIncomingPendingConnections: MAX_INCOMING_PENDING_CONNECTIONS +} + +export interface DefaultConnectionManagerComponents { + peerId: PeerId + metrics?: Metrics + peerStore: PeerStore + peerRouting: PeerRouting + transportManager: TransportManager + connectionGater: ConnectionGater + events: TypedEventTarget + logger: ComponentLogger +} + +/** + * Responsible for managing known connections. + */ +export class DefaultConnectionManager implements ConnectionManager, Startable { + private started: boolean + private readonly connections: PeerMap + private readonly allow: IpNet[] + private readonly deny: IpNet[] + private readonly maxIncomingPendingConnections: number + private incomingPendingConnections: number + private outboundPendingConnections: number + private maxConnections: number + + public readonly dialQueue: DialQueue + public readonly reconnectQueue: ReconnectQueue + public readonly connectionPruner: ConnectionPruner + private readonly inboundConnectionRateLimiter: RateLimiter + private readonly peerStore: PeerStore + private readonly metrics?: Metrics + private readonly events: TypedEventTarget + private readonly log: Logger + private readonly peerId: PeerId + + constructor (components: DefaultConnectionManagerComponents, init: ConnectionManagerInit = {}) { + this.maxConnections = init.maxConnections ?? defaultOptions.maxConnections + + if (this.maxConnections < 1) { + throw new InvalidParametersError('Connection Manager maxConnections must be greater than 0') + } + + /** + * Map of connections per peer + */ + this.connections = new PeerMap() + + this.started = false + this.peerId = components.peerId + this.peerStore = components.peerStore + this.metrics = components.metrics + this.events = components.events + this.log = components.logger.forComponent('libp2p:connection-manager') + + this.onConnect = this.onConnect.bind(this) + this.onDisconnect = this.onDisconnect.bind(this) + + // allow/deny lists + this.allow = (init.allow ?? []).map(str => multiaddrToIpNet(str)) + this.deny = (init.deny ?? []).map(str => multiaddrToIpNet(str)) + + this.incomingPendingConnections = 0 + this.maxIncomingPendingConnections = init.maxIncomingPendingConnections ?? defaultOptions.maxIncomingPendingConnections + this.outboundPendingConnections = 0 + + // controls individual peers trying to dial us too quickly + this.inboundConnectionRateLimiter = new RateLimiter({ + points: init.inboundConnectionThreshold ?? defaultOptions.inboundConnectionThreshold, + duration: 1 + }) + + // controls what happens when we have too many connections + this.connectionPruner = new ConnectionPruner({ + connectionManager: this, + peerStore: components.peerStore, + events: components.events, + logger: components.logger + }, { + allow: init.allow?.map(a => multiaddr(a)) + }) + + this.dialQueue = new DialQueue(components, { + addressSorter: init.addressSorter, + maxParallelDials: init.maxParallelDials ?? MAX_PARALLEL_DIALS, + maxDialQueueLength: init.maxDialQueueLength ?? MAX_DIAL_QUEUE_LENGTH, + maxPeerAddrsToDial: init.maxPeerAddrsToDial ?? MAX_PEER_ADDRS_TO_DIAL, + dialTimeout: init.dialTimeout ?? DIAL_TIMEOUT, + resolvers: init.resolvers ?? { + dnsaddr: dnsaddrResolver + }, + connections: this.connections + }) + + this.reconnectQueue = new ReconnectQueue({ + events: components.events, + peerStore: components.peerStore, + logger: components.logger, + connectionManager: this + }, { + retries: init.reconnectRetries, + retryInterval: init.reconnectRetryInterval, + backoffFactor: init.reconnectBackoffFactor, + maxParallelReconnects: init.maxParallelReconnects + }) + } + + readonly [Symbol.toStringTag] = '@libp2p/connection-manager' + + /** + * Starts the Connection Manager. If Metrics are not enabled on libp2p + * only event loop and connection limits will be monitored. + */ + async start (): Promise { + // track inbound/outbound connections + this.metrics?.registerMetricGroup('libp2p_connection_manager_connections', { + calculate: () => { + const metric = { + inbound: 0, + 'inbound pending': this.incomingPendingConnections, + outbound: 0, + 'outbound pending': this.outboundPendingConnections + } + + for (const conns of this.connections.values()) { + for (const conn of conns) { + metric[conn.direction]++ + } + } + + return metric + } + }) + + // track total number of streams per protocol + this.metrics?.registerMetricGroup('libp2p_protocol_streams_total', { + label: 'protocol', + calculate: () => { + const metric: Record = {} + + for (const conns of this.connections.values()) { + for (const conn of conns) { + for (const stream of conn.streams) { + const key = `${stream.direction} ${stream.protocol ?? 'unnegotiated'}` + + metric[key] = (metric[key] ?? 0) + 1 + } + } + } + + return metric + } + }) + + // track 90th percentile of streams per protocol + this.metrics?.registerMetricGroup('libp2p_connection_manager_protocol_streams_per_connection_90th_percentile', { + label: 'protocol', + calculate: () => { + const allStreams: Record = {} + + for (const conns of this.connections.values()) { + for (const conn of conns) { + const streams: Record = {} + + for (const stream of conn.streams) { + const key = `${stream.direction} ${stream.protocol ?? 'unnegotiated'}` + + streams[key] = (streams[key] ?? 0) + 1 + } + + for (const [protocol, count] of Object.entries(streams)) { + allStreams[protocol] = allStreams[protocol] ?? [] + allStreams[protocol].push(count) + } + } + } + + const metric: Record = {} + + for (let [protocol, counts] of Object.entries(allStreams)) { + counts = counts.sort((a, b) => a - b) + + const index = Math.floor(counts.length * 0.9) + metric[protocol] = counts[index] + } + + return metric + } + }) + + this.events.addEventListener('connection:open', this.onConnect) + this.events.addEventListener('connection:close', this.onDisconnect) + + await start( + this.dialQueue, + this.reconnectQueue, + this.connectionPruner + ) + + this.started = true + this.log('started') + } + + /** + * Stops the Connection Manager + */ + async stop (): Promise { + this.events.removeEventListener('connection:open', this.onConnect) + this.events.removeEventListener('connection:close', this.onDisconnect) + + await stop( + this.reconnectQueue, + this.dialQueue, + this.connectionPruner + ) + + // Close all connections we're tracking + const tasks: Array> = [] + for (const connectionList of this.connections.values()) { + for (const connection of connectionList) { + tasks.push((async () => { + try { + await connection.close() + } catch (err) { + this.log.error(err) + } + })()) + } + } + + this.log('closing %d connections', tasks.length) + await Promise.all(tasks) + this.connections.clear() + + this.log('stopped') + } + + getMaxConnections (): number { + return this.maxConnections + } + + setMaxConnections (maxConnections: number): void { + if (this.maxConnections < 1) { + throw new InvalidParametersError('Connection Manager maxConnections must be greater than 0') + } + + let needsPrune = false + + if (maxConnections < this.maxConnections) { + needsPrune = true + } + + this.maxConnections = maxConnections + + if (needsPrune) { + this.connectionPruner.maybePruneConnections() + } + } + + onConnect (evt: CustomEvent): void { + void this._onConnect(evt).catch(err => { + this.log.error(err) + }) + } + + /** + * Tracks the incoming connection and check the connection limit + */ + async _onConnect (evt: CustomEvent): Promise { + const { detail: connection } = evt + + if (!this.started) { + // This can happen when we are in the process of shutting down the node + await connection.close() + return + } + + if (connection.status !== 'open') { + // this can happen when the remote closes the connection immediately after + // opening + return + } + + const peerId = connection.remotePeer + const isNewPeer = !this.connections.has(peerId) + const storedConns = this.connections.get(peerId) ?? [] + storedConns.push(connection) + + this.connections.set(peerId, storedConns) + + // only need to store RSA public keys, all other types are embedded in the peer id + if (peerId.publicKey != null && peerId.type === 'RSA') { + await this.peerStore.patch(peerId, { + publicKey: peerId.publicKey + }) + } + + if (isNewPeer) { + this.events.safeDispatchEvent('peer:connect', { detail: connection.remotePeer }) + } + } + + /** + * Removes the connection from tracking + */ + onDisconnect (evt: CustomEvent): void { + const { detail: connection } = evt + const peerId = connection.remotePeer + const peerConns = this.connections.get(peerId) ?? [] + + // remove closed connection + const filteredPeerConns = peerConns.filter(conn => conn.id !== connection.id) + + // update peer connections + this.connections.set(peerId, filteredPeerConns) + + if (filteredPeerConns.length === 0) { + // trigger disconnect event if no connections remain + this.log.trace('peer %p disconnected, removing connection map entry', peerId) + this.connections.delete(peerId) + + // broadcast disconnect event + this.events.safeDispatchEvent('peer:disconnect', { detail: connection.remotePeer }) + } + } + + getConnections (peerId?: PeerId): Connection[] { + if (peerId != null) { + return this.connections.get(peerId) ?? [] + } + + let conns: Connection[] = [] + + for (const c of this.connections.values()) { + conns = conns.concat(c) + } + + return conns + } + + getConnectionsMap (): PeerMap { + return this.connections + } + + async openConnection (peerIdOrMultiaddr: PeerId | Multiaddr | Multiaddr[], options: OpenConnectionOptions = {}): Promise { + if (!this.started) { + throw new NotStartedError('Not started') + } + + this.outboundPendingConnections++ + + try { + options.signal?.throwIfAborted() + + const { peerId } = getPeerAddress(peerIdOrMultiaddr) + + if (this.peerId.equals(peerId)) { + throw new InvalidPeerIdError('Can not dial self') + } + + if (peerId != null && options.force !== true) { + this.log('dial %p', peerId) + const existingConnection = this.getConnections(peerId) + .find(conn => conn.limits == null) + + if (existingConnection != null) { + this.log('had an existing non-limited connection to %p as %a', peerId, existingConnection.remoteAddr) + + options.onProgress?.(new CustomProgressEvent('dial-queue:already-connected')) + return existingConnection + } + } + + const connection = await this.dialQueue.dial(peerIdOrMultiaddr, { + ...options, + priority: options.priority ?? DEFAULT_DIAL_PRIORITY + }) + + if (connection.status !== 'open') { + throw new ConnectionClosedError('Remote closed connection during opening') + } + + let peerConnections = this.connections.get(connection.remotePeer) + + if (peerConnections == null) { + peerConnections = [] + this.connections.set(connection.remotePeer, peerConnections) + } + + // we get notified of connections via the Upgrader emitting "connection" + // events, double check we aren't already tracking this connection before + // storing it + let trackedConnection = false + + for (const conn of peerConnections) { + if (conn.id === connection.id) { + trackedConnection = true + } + + // make sure we don't already have a connection to this multiaddr + if (options.force !== true && conn.id !== connection.id && conn.remoteAddr.equals(connection.remoteAddr)) { + connection.abort(new InvalidMultiaddrError('Duplicate multiaddr connection')) + + // return the existing connection + return conn + } + } + + if (!trackedConnection) { + peerConnections.push(connection) + } + + return connection + } finally { + this.outboundPendingConnections-- + } + } + + async closeConnections (peerId: PeerId, options: AbortOptions = {}): Promise { + const connections = this.connections.get(peerId) ?? [] + + await Promise.all( + connections.map(async connection => { + try { + await connection.close(options) + } catch (err: any) { + connection.abort(err) + } + }) + ) + } + + acceptIncomingConnection (maConn: MultiaddrConnection): boolean { + // check deny list + const denyConnection = this.deny.some(ma => { + return ma.contains(maConn.remoteAddr.nodeAddress().address) + }) + + if (denyConnection) { + this.log('connection from %a refused - connection remote address was in deny list', maConn.remoteAddr) + return false + } + + // check allow list + const allowConnection = this.allow.some(ipNet => { + return ipNet.contains(maConn.remoteAddr.nodeAddress().address) + }) + + if (allowConnection) { + this.incomingPendingConnections++ + + return true + } + + // check pending connections + if (this.incomingPendingConnections === this.maxIncomingPendingConnections) { + this.log('connection from %a refused - incomingPendingConnections exceeded by host', maConn.remoteAddr) + return false + } + + if (maConn.remoteAddr.isThinWaistAddress()) { + const host = maConn.remoteAddr.nodeAddress().address + + try { + this.inboundConnectionRateLimiter.consume(host, 1) + } catch { + this.log('connection from %a refused - inboundConnectionThreshold exceeded by host %s', maConn.remoteAddr, host) + return false + } + } + + if (this.getConnections().length < this.maxConnections) { + this.incomingPendingConnections++ + + return true + } + + this.log('connection from %a refused - maxConnections exceeded', maConn.remoteAddr) + return false + } + + afterUpgradeInbound (): void { + this.incomingPendingConnections-- + } + + getDialQueue (): PendingDial[] { + const statusMap: Record = { + queued: 'queued', + running: 'active', + errored: 'error', + complete: 'success' + } + + return this.dialQueue.queue.queue.map(job => { + return { + id: job.id, + status: statusMap[job.status], + peerId: job.options.peerId, + multiaddrs: [...job.options.multiaddrs].map(ma => multiaddr(ma)) + } + }) + } + + async isDialable (multiaddr: Multiaddr | Multiaddr[], options: IsDialableOptions = {}): Promise { + return this.dialQueue.isDialable(multiaddr, options) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/reconnect-queue.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/reconnect-queue.ts new file mode 100644 index 000000000..5158f6ee7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/reconnect-queue.ts @@ -0,0 +1,166 @@ +import { KEEP_ALIVE } from '@libp2p/interface' +import { PeerQueue } from '@libp2p/utils' +import pRetry from 'p-retry' +import { MAX_PARALLEL_RECONNECTS } from './constants.js' +import type { ComponentLogger, Libp2pEvents, Logger, Metrics, Peer, PeerId, PeerStore, Startable } from '@libp2p/interface' +import type { ConnectionManager } from '@libp2p/interface-internal' +import type { TypedEventTarget } from 'main-event' + +export interface ReconnectQueueComponents { + connectionManager: ConnectionManager + events: TypedEventTarget + peerStore: PeerStore + logger: ComponentLogger + metrics?: Metrics +} + +export interface ReconnectQueueInit { + retries?: number + retryInterval?: number + backoffFactor?: number + maxParallelReconnects?: number +} + +/** + * When peers tagged with `KEEP_ALIVE` disconnect, this component attempts to + * redial them + */ +export class ReconnectQueue implements Startable { + private readonly log: Logger + private readonly queue: PeerQueue + private started: boolean + private readonly peerStore: PeerStore + private readonly retries: number + private readonly retryInterval?: number + private readonly backoffFactor?: number + private readonly connectionManager: ConnectionManager + private readonly events: TypedEventTarget + + constructor (components: ReconnectQueueComponents, init: ReconnectQueueInit = {}) { + this.log = components.logger.forComponent('libp2p:reconnect-queue') + this.peerStore = components.peerStore + this.connectionManager = components.connectionManager + this.queue = new PeerQueue({ + concurrency: init.maxParallelReconnects ?? MAX_PARALLEL_RECONNECTS, + metricName: 'libp2p_reconnect_queue', + metrics: components.metrics + }) + this.started = false + this.retries = init.retries ?? 5 + this.backoffFactor = init.backoffFactor + this.retryInterval = init.retryInterval + this.events = components.events + + components.events.addEventListener('peer:disconnect', (evt) => { + this.maybeReconnect(evt.detail) + .catch(err => { + this.log.error('failed to maybe reconnect to %p - %e', evt.detail, err) + }) + }) + } + + private async maybeReconnect (peerId: PeerId): Promise { + if (!this.started) { + return + } + + const peer = await this.peerStore.get(peerId) + + if (!hasKeepAliveTag(peer)) { + return + } + + if (this.queue.has(peerId)) { + return + } + + this.queue.add(async (options) => { + await pRetry(async (attempt) => { + if (!this.started) { + return + } + + try { + await this.connectionManager.openConnection(peerId, { + signal: options?.signal + }) + } catch (err) { + this.log('reconnecting to %p attempt %d of %d failed - %e', peerId, attempt, this.retries, err) + throw err + } + }, { + signal: options?.signal, + retries: this.retries, + factor: this.backoffFactor, + minTimeout: this.retryInterval + }) + }, { + peerId + }) + .catch(async err => { + this.log.error('failed to reconnect to %p - %e', peerId, err) + + const tags: Record = {} + + ;[...peer.tags.keys()].forEach(key => { + if (key.startsWith(KEEP_ALIVE)) { + tags[key] = undefined + } + }) + + await this.peerStore.merge(peerId, { + tags + }) + + this.events.safeDispatchEvent('peer:reconnect-failure', { + detail: peerId + }) + }) + .catch(async err => { + this.log.error('failed to remove keep-alive tag from %p - %e', peerId, err) + }) + } + + start (): void { + this.started = true + } + + async afterStart (): Promise { + // re-connect to any peers with the KEEP_ALIVE tag + void Promise.resolve() + .then(async () => { + const keepAlivePeers: Peer[] = await this.peerStore.all({ + filters: [ + (peer) => hasKeepAliveTag(peer) + ] + }) + + await Promise.all( + keepAlivePeers.map(async peer => { + await this.connectionManager.openConnection(peer.id) + .catch(err => { + this.log.error(err) + }) + }) + ) + }) + .catch(err => { + this.log.error(err) + }) + } + + stop (): void { + this.started = false + this.queue.abort() + } +} + +function hasKeepAliveTag (peer: Peer): boolean { + for (const tag of peer.tags.keys()) { + if (tag.startsWith(KEEP_ALIVE)) { + return true + } + } + + return false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/resolvers/dnsaddr.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/resolvers/dnsaddr.ts new file mode 100644 index 000000000..aea0833bf --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/resolvers/dnsaddr.ts @@ -0,0 +1,69 @@ +import { dns, RecordType } from '@multiformats/dns' +import { multiaddr } from '@multiformats/multiaddr' +import type { MultiaddrResolver, MultiaddrResolveOptions } from '@libp2p/interface' +import type { DNS } from '@multiformats/dns' +import type { Multiaddr } from '@multiformats/multiaddr' + +class DNSAddrResolver implements MultiaddrResolver { + private dns?: DNS + + canResolve (ma: Multiaddr): boolean { + return ma.getComponents().some(({ name }) => name === 'dnsaddr') + } + + async resolve (ma: Multiaddr, options: MultiaddrResolveOptions): Promise { + const hostname = ma.getComponents() + .find(component => component.name === 'dnsaddr') + ?.value + + if (hostname == null) { + return [ma] + } + + const resolver = this.getDNS(options) + const result = await resolver.query(`_dnsaddr.${hostname}`, { + signal: options?.signal, + types: [ + RecordType.TXT + ] + }) + + const peerId = ma.getComponents() + .find(component => component.name === 'p2p') + ?.value + const output: Multiaddr[] = [] + + for (const answer of result.Answer) { + const addr = answer.data + .replace(/["']/g, '') + .trim() + .split('=')[1] + + if (addr == null) { + continue + } + + if (peerId != null && !addr.includes(peerId)) { + continue + } + + output.push(multiaddr(addr)) + } + + return output + } + + private getDNS (options: MultiaddrResolveOptions): DNS { + if (options.dns != null) { + return options.dns + } + + if (this.dns == null) { + this.dns = dns() + } + + return this.dns + } +} + +export const dnsaddrResolver = new DNSAddrResolver() diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/resolvers/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/resolvers/index.ts new file mode 100644 index 000000000..7496b17bf --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/resolvers/index.ts @@ -0,0 +1,59 @@ +import { RecursionLimitError } from '../../errors.ts' +import { MAX_RECURSIVE_DEPTH } from '../constants.defaults.ts' +import type { MultiaddrResolveOptions, MultiaddrResolver } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +export interface ResolveOptions extends MultiaddrResolveOptions { + /** + * When resolving DNSADDR Multiaddrs that resolve to other DNSADDR Multiaddrs, + * limit how many times we will recursively resolve them. + * + * @default 32 + */ + maxRecursiveDepth?: number + + /** + * The current recursive depth + * + * @default 0 + */ + depth?: number +} + +/** + * Recursively resolve multiaddrs + */ +export async function resolveMultiaddr (address: Multiaddr, resolvers: Record, options: ResolveOptions): Promise { + const depth = options.depth ?? 0 + + if (depth > (options.maxRecursiveDepth ?? MAX_RECURSIVE_DEPTH)) { + throw new RecursionLimitError('Max recursive depth reached') + } + + let resolved = false + const output: Multiaddr[] = [] + + for (const resolver of Object.values(resolvers)) { + if (resolver.canResolve(address)) { + resolved = true + const addresses = await resolver.resolve(address, options) + + for (const address of addresses) { + output.push( + ...(await resolveMultiaddr(address, resolvers, { + ...options, + depth: depth + 1 + })) + ) + } + } + } + + if (resolved === false) { + output.push(address) + } + + return output +} + +export { dnsaddrResolver } from './dnsaddr.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/utils.ts new file mode 100644 index 000000000..09ce3f63e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-manager/utils.ts @@ -0,0 +1,91 @@ +import { multiaddr } from '@multiformats/multiaddr' +import { convertToIpNet } from '@multiformats/multiaddr/convert' +import type { IpNet } from '@chainsafe/netmask' +import type { Connection, AbortOptions } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * These are speculative protocols that are run automatically on connection open + * so are usually not the reason the connection was opened. + * + * Consequently when requested it should be safe to close connections that only + * have these protocol streams open. + */ +const DEFAULT_CLOSABLE_PROTOCOLS = [ + // identify + '/ipfs/id/1.0.0', + + // identify-push + '/ipfs/id/push/1.0.0', + + // autonat + '/libp2p/autonat/1.0.0', + + // dcutr + '/libp2p/dcutr' +] + +export interface SafelyCloseConnectionOptions extends AbortOptions { + /** + * Only close the stream if it either has no protocol streams open or only + * ones in this list. + * + * @default ['/ipfs/id/1.0.0'] + */ + closableProtocols?: string[] +} + +/** + * Close the passed connection if it has no streams, or only closable protocol + * streams, falling back to aborting the connection if closing it cleanly fails. + */ +export async function safelyCloseConnectionIfUnused (connection?: Connection, options?: SafelyCloseConnectionOptions): Promise { + const streamProtocols = connection?.streams?.map(stream => stream.protocol) ?? [] + const closableProtocols = options?.closableProtocols ?? DEFAULT_CLOSABLE_PROTOCOLS + + // if the connection has protocols not in the closable protocols list, do not + // close the connection + if (streamProtocols.filter(proto => proto != null && !closableProtocols.includes(proto)).length > 0) { + return + } + + try { + await connection?.close(options) + } catch (err: any) { + connection?.abort(err) + } +} + +/** + * Converts a multiaddr string or object to an IpNet object. + * If the multiaddr doesn't include /ipcidr, it will encapsulate with the appropriate CIDR: + * - /ipcidr/32 for IPv4 + * - /ipcidr/128 for IPv6 + * + * @param {string | Multiaddr} ma - The multiaddr string or object to convert. + * @returns {IpNet} The converted IpNet object. + * @throws {Error} Throws an error if the multiaddr is not valid. + */ +export function multiaddrToIpNet (ma: string | Multiaddr): IpNet { + try { + let parsedMa: Multiaddr + if (typeof ma === 'string') { + parsedMa = multiaddr(ma) + } else { + parsedMa = ma + } + + const protoNames = new Set([...parsedMa.getComponents().map(component => component.name)]) + + // Check if /ipcidr is already present + if (!protoNames.has('ipcidr')) { + const isIPv6 = protoNames.has('ip6') + const cidr = isIPv6 ? '/ipcidr/128' : '/ipcidr/32' + parsedMa = parsedMa.encapsulate(cidr) + } + + return convertToIpNet(parsedMa) + } catch (error) { + throw new Error(`Can't convert to IpNet, Invalid multiaddr format: ${ma}`) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-monitor.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-monitor.ts new file mode 100644 index 000000000..f4e7afcf6 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection-monitor.ts @@ -0,0 +1,158 @@ +import { randomBytes } from '@libp2p/crypto' +import { serviceCapabilities } from '@libp2p/interface' +import { AdaptiveTimeout, byteStream } from '@libp2p/utils' +import { setMaxListeners } from 'main-event' +import type { ComponentLogger, Logger, Metrics, Startable } from '@libp2p/interface' +import type { ConnectionManager } from '@libp2p/interface-internal' +import type { AdaptiveTimeoutInit } from '@libp2p/utils' + +const DEFAULT_PING_INTERVAL_MS = 10000 +const PROTOCOL_VERSION = '1.0.0' +const PROTOCOL_NAME = 'ping' +const PROTOCOL_PREFIX = 'ipfs' +const PING_LENGTH = 32 +const DEFAULT_ABORT_CONNECTION_ON_PING_FAILURE = true + +export interface ConnectionMonitorInit { + /** + * Whether the connection monitor is enabled + * + * @default true + */ + enabled?: boolean + + /** + * How often to ping remote peers in ms + * + * @default 10000 + */ + pingInterval?: number + + /** + * Timeout settings for how long the ping is allowed to take before the + * connection will be judged inactive and aborted. + * + * The timeout is adaptive to cope with slower networks or nodes that + * have changing network characteristics, such as mobile. + */ + pingTimeout?: Omit + + /** + * If true, any connection that fails the ping will be aborted + * + * @default true + */ + abortConnectionOnPingFailure?: boolean + + /** + * Override the ping protocol prefix + * + * @default 'ipfs' + */ + protocolPrefix?: string +} + +export interface ConnectionMonitorComponents { + logger: ComponentLogger + connectionManager: ConnectionManager + metrics?: Metrics +} + +export class ConnectionMonitor implements Startable { + private readonly protocol: string + private readonly components: ConnectionMonitorComponents + private readonly log: Logger + private heartbeatInterval?: ReturnType + private readonly pingIntervalMs: number + private abortController?: AbortController + private readonly timeout: AdaptiveTimeout + private readonly abortConnectionOnPingFailure: boolean + + constructor (components: ConnectionMonitorComponents, init: ConnectionMonitorInit = {}) { + this.components = components + this.protocol = `/${init.protocolPrefix ?? PROTOCOL_PREFIX}/${PROTOCOL_NAME}/${PROTOCOL_VERSION}` + + this.log = components.logger.forComponent('libp2p:connection-monitor') + this.pingIntervalMs = init.pingInterval ?? DEFAULT_PING_INTERVAL_MS + this.abortConnectionOnPingFailure = init.abortConnectionOnPingFailure ?? DEFAULT_ABORT_CONNECTION_ON_PING_FAILURE + this.timeout = new AdaptiveTimeout({ + ...(init.pingTimeout ?? {}), + metrics: components.metrics, + metricName: 'libp2p_connection_monitor_ping_time_milliseconds' + }) + } + + readonly [Symbol.toStringTag] = '@libp2p/connection-monitor' + + readonly [serviceCapabilities]: string[] = [ + '@libp2p/connection-monitor' + ] + + start (): void { + this.abortController = new AbortController() + setMaxListeners(Infinity, this.abortController.signal) + + this.heartbeatInterval = setInterval(() => { + this.components.connectionManager.getConnections().forEach(conn => { + Promise.resolve().then(async () => { + let start = Date.now() + try { + const signal = this.timeout.getTimeoutSignal({ + signal: this.abortController?.signal + }) + const stream = await conn.newStream(this.protocol, { + signal, + runOnLimitedConnection: true + }) + const bs = byteStream(stream) + start = Date.now() + + await Promise.all([ + bs.write(randomBytes(PING_LENGTH), { + signal + }), + bs.read({ + bytes: PING_LENGTH, + signal + }) + ]) + + conn.rtt = Date.now() - start + + await stream.closeWrite({ + signal + }) + } catch (err: any) { + if (err.name !== 'UnsupportedProtocolError') { + throw err + } + + // protocol was unsupported, but that's ok as it means the remote + // peer was still alive. We ran multistream-select which means two + // round trips (e.g. 1x for the mss header, then another for the + // protocol) so divide the time it took by two + conn.rtt = (Date.now() - start) / 2 + } + }) + .catch(err => { + this.log.error('error during heartbeat', err) + + if (this.abortConnectionOnPingFailure) { + this.log.error('aborting connection due to ping failure') + conn.abort(err) + } else { + this.log('connection ping failed, but not aborting due to abortConnectionOnPingFailure flag') + } + }) + }) + }, this.pingIntervalMs) + } + + stop (): void { + this.abortController?.abort() + + if (this.heartbeatInterval != null) { + clearInterval(this.heartbeatInterval) + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection.ts new file mode 100644 index 000000000..349248f13 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/connection.ts @@ -0,0 +1,332 @@ +import { connectionSymbol, LimitedConnectionError, ConnectionClosedError, ConnectionClosingError, TooManyOutboundProtocolStreamsError, TooManyInboundProtocolStreamsError, StreamCloseEvent, StreamMessageEvent } from '@libp2p/interface' +import * as mss from '@libp2p/multistream-select' +import { CODE_P2P } from '@multiformats/multiaddr' +import { setMaxListeners, TypedEventEmitter } from 'main-event' +import { PROTOCOL_NEGOTIATION_TIMEOUT } from './connection-manager/constants.defaults.ts' +import { MuxerUnavailableError } from './errors.ts' +import { DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS } from './registrar.ts' +import type { AbortOptions, Logger, MessageStreamDirection, Connection as ConnectionInterface, Stream, NewStreamOptions, PeerId, ConnectionLimits, StreamMuxer, Metrics, PeerStore, MultiaddrConnection, MessageStreamEvents, MultiaddrConnectionTimeline, ConnectionStatus, MessageStream } from '@libp2p/interface' +import type { Registrar } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Uint8ArrayList } from 'uint8arraylist' + +const CLOSE_TIMEOUT = 500 + +export interface ConnectionComponents { + peerStore: PeerStore + registrar: Registrar + metrics?: Metrics +} + +export interface ConnectionInit { + id: string + maConn: MultiaddrConnection + stream: MessageStream + remotePeer: PeerId + direction?: MessageStreamDirection + muxer?: StreamMuxer + cryptoProtocol?: string + limits?: ConnectionLimits + outboundStreamProtocolNegotiationTimeout?: number + inboundStreamProtocolNegotiationTimeout?: number +} + +/** + * An implementation of the js-libp2p connection. + * Any libp2p transport should use an upgrader to return this connection. + */ +export class Connection extends TypedEventEmitter implements ConnectionInterface { + public readonly id: string + public readonly remoteAddr: Multiaddr + public readonly remotePeer: PeerId + public direction: MessageStreamDirection + public timeline: MultiaddrConnectionTimeline + public multiplexer?: string + public encryption?: string + public status: ConnectionStatus + public limits?: ConnectionLimits + public readonly log: Logger + + private readonly maConn: MultiaddrConnection + private readonly muxer?: StreamMuxer + private readonly components: ConnectionComponents + private readonly outboundStreamProtocolNegotiationTimeout: number + private readonly inboundStreamProtocolNegotiationTimeout: number + + constructor (components: ConnectionComponents, init: ConnectionInit) { + super() + + this.components = components + + this.id = init.id + this.remoteAddr = init.maConn.remoteAddr + this.remotePeer = init.remotePeer + this.direction = init.direction ?? 'outbound' + this.status = 'open' + this.timeline = init.maConn.timeline + this.encryption = init.cryptoProtocol + this.limits = init.limits + this.maConn = init.maConn + this.log = init.maConn.log + this.outboundStreamProtocolNegotiationTimeout = init.outboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT + this.inboundStreamProtocolNegotiationTimeout = init.inboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT + + this.onIncomingStream = this.onIncomingStream.bind(this) + + if (this.remoteAddr.getComponents().find(component => component.code === CODE_P2P) == null) { + this.remoteAddr = this.remoteAddr.encapsulate(`/p2p/${this.remotePeer}`) + } + + if (init.muxer != null) { + this.multiplexer = init.muxer.protocol + this.muxer = init.muxer + this.muxer.addEventListener('stream', this.onIncomingStream) + } + + this.maConn.addEventListener('close', (evt) => { + this.dispatchEvent(new StreamCloseEvent(evt.local, evt.error)) + }) + } + + readonly [Symbol.toStringTag] = 'Connection' + + readonly [connectionSymbol] = true + + get streams (): Stream[] { + return this.muxer?.streams ?? [] + } + + /** + * Create a new stream over this connection + */ + newStream = async (protocols: string[], options: NewStreamOptions = {}): Promise => { + if (this.status != 'open') { + throw new ConnectionClosedError(`The connection is "${this.status}" and not "open"`) + } + + if (!Array.isArray(protocols)) { + protocols = [protocols] + } + + if (this.limits != null && options?.runOnLimitedConnection !== true) { + throw new LimitedConnectionError('Cannot open protocol stream on limited connection') + } + + if (this.muxer == null) { + throw new MuxerUnavailableError('Connection is not multiplexed') + } + + this.log.trace('starting new stream for protocols %s', protocols) + const muxedStream = await this.muxer.createStream({ + ...options, + + // most underlying transports only support negotiating a single protocol + // so only pass the early protocol if a single protocol has been requested + // otherwise fall back to mss + protocol: protocols.length === 1 ? protocols[0] : undefined + }) + this.log.trace('started new stream %s for protocols %s', muxedStream.id, protocols) + + try { + if (options.signal == null) { + muxedStream.log('no abort signal was passed while trying to negotiate protocols %s falling back to default timeout', protocols) + + const signal = AbortSignal.timeout(this.outboundStreamProtocolNegotiationTimeout) + setMaxListeners(Infinity, signal) + + options = { + ...options, + signal + } + } + + if (muxedStream.protocol === '') { + muxedStream.log.trace('selecting protocol from protocols %s', protocols) + + muxedStream.protocol = await mss.select(muxedStream, protocols, options) + + muxedStream.log('negotiated protocol %s', muxedStream.protocol) + } else { + muxedStream.log('pre-negotiated protocol %s', muxedStream.protocol) + } + + const outgoingLimit = findOutgoingStreamLimit(muxedStream.protocol, this.components.registrar, options) + const streamCount = countStreams(muxedStream.protocol, 'outbound', this) + + if (streamCount > outgoingLimit) { + const err = new TooManyOutboundProtocolStreamsError(`Too many outbound protocol streams for protocol "${muxedStream.protocol}" - ${streamCount}/${outgoingLimit}`) + muxedStream.abort(err) + + throw err + } + + // If a protocol stream has been successfully negotiated and is to be passed to the application, + // the peer store should ensure that the peer is registered with that protocol + await this.components.peerStore.merge(this.remotePeer, { + protocols: [muxedStream.protocol] + }) + + this.components.metrics?.trackProtocolStream(muxedStream) + + return muxedStream + } catch (err: any) { + if (muxedStream.status === 'open') { + muxedStream.abort(err) + } else { + this.log.error('could not create new outbound stream on connection %s %a for protocols %s - %e', this.direction === 'inbound' ? 'from' : 'to', this.remoteAddr, protocols, err) + } + + throw err + } + } + + private async onIncomingStream (evt: CustomEvent): Promise { + this.log('new incoming stream %s', evt.detail.id) + const muxedStream = evt.detail + + const signal = AbortSignal.timeout(this.inboundStreamProtocolNegotiationTimeout) + setMaxListeners(Infinity, signal) + + this.log('start protocol negotiation %s', evt.detail.id) + + try { + if (muxedStream.protocol === '') { + const protocols = this.components.registrar.getProtocols() + + muxedStream.log.trace('selecting protocol from protocols %s', protocols) + + muxedStream.protocol = await mss.handle(muxedStream, protocols, { + signal + }) + + muxedStream.log('negotiated protocol %s', muxedStream.protocol) + } else { + muxedStream.log('pre-negotiated protocol %s', muxedStream.protocol) + } + + const incomingLimit = findIncomingStreamLimit(muxedStream.protocol, this.components.registrar) + const streamCount = countStreams(muxedStream.protocol, 'inbound', this) + + if (streamCount > incomingLimit) { + throw new TooManyInboundProtocolStreamsError(`Too many inbound protocol streams for protocol "${muxedStream.protocol}" - limit ${incomingLimit}`) + } + + // If a protocol stream has been successfully negotiated and is to be passed to the application, + // the peer store should ensure that the peer is registered with that protocol + await this.components.peerStore.merge(this.remotePeer, { + protocols: [muxedStream.protocol] + }, { + signal + }) + + this.components.metrics?.trackProtocolStream(muxedStream) + + const { handler, options } = this.components.registrar.getHandler(muxedStream.protocol) + + if (this.limits != null && options.runOnLimitedConnection !== true) { + throw new LimitedConnectionError('Cannot open protocol stream on limited connection') + } + + await handler(muxedStream, this) + } catch (err: any) { + muxedStream.abort(err) + } + } + + /** + * Close the connection + */ + async close (options: AbortOptions = {}): Promise { + if (this.status !== 'open') { + return + } + + this.log('closing connection to %a', this.remoteAddr) + + this.status = 'closed' + + if (options.signal == null) { + const signal = AbortSignal.timeout(CLOSE_TIMEOUT) + setMaxListeners(Infinity, signal) + + options = { + ...options, + signal + } + } + + try { + this.log.trace('closing underlying transport') + + // close the underlying transport + await this.maConn.closeWrite(options) + + this.log.trace('updating timeline with close time') + + this.status = 'closed' + this.timeline.close = Date.now() + } catch (err: any) { + this.log.error('error encountered during graceful close of connection to %a', this.remoteAddr, err) + this.abort(err) + } + } + + abort (err: Error): void { + if (this.status !== 'open') { + return + } + + this.status = 'aborted' + + // abort the underlying transport + this.maConn.abort(err) + } +} + +export function createConnection (components: ConnectionComponents, init: ConnectionInit): ConnectionInterface { + return new Connection(components, init) +} + +function findIncomingStreamLimit (protocol: string, registrar: Registrar): number { + try { + const { options } = registrar.getHandler(protocol) + + if (options.maxInboundStreams != null) { + return options.maxInboundStreams + } + } catch (err: any) { + if (err.name !== 'UnhandledProtocolError') { + throw err + } + } + + return DEFAULT_MAX_INBOUND_STREAMS +} + +function findOutgoingStreamLimit (protocol: string, registrar: Registrar, options: NewStreamOptions = {}): number { + try { + const { options } = registrar.getHandler(protocol) + + if (options.maxOutboundStreams != null) { + return options.maxOutboundStreams + } + } catch (err: any) { + if (err.name !== 'UnhandledProtocolError') { + throw err + } + } + + return options.maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS +} + +function countStreams (protocol: string, direction: 'inbound' | 'outbound', connection: Connection): number { + let streamCount = 0 + + connection.streams.forEach(stream => { + if (stream.direction === direction && stream.protocol === protocol) { + streamCount++ + } + }) + + return streamCount +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/content-routing.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/content-routing.ts new file mode 100644 index 000000000..a0f58ca13 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/content-routing.ts @@ -0,0 +1,200 @@ +import { NotStartedError } from '@libp2p/interface' +import { PeerSet } from '@libp2p/peer-collections' +import merge from 'it-merge' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { NoContentRoutersError } from './errors.js' +import type { AbortOptions, ComponentLogger, ContentRouting, Metrics, PeerInfo, PeerRouting, PeerStore, RoutingOptions, Startable } from '@libp2p/interface' +import type { CID } from 'multiformats/cid' + +export interface CompoundContentRoutingInit { + routers: ContentRouting[] +} + +export interface CompoundContentRoutingComponents { + peerStore: PeerStore + peerRouting: PeerRouting + logger: ComponentLogger + metrics?: Metrics +} + +export class CompoundContentRouting implements ContentRouting, Startable { + private readonly routers: ContentRouting[] + private started: boolean + private readonly components: CompoundContentRoutingComponents + + constructor (components: CompoundContentRoutingComponents, init: CompoundContentRoutingInit) { + this.routers = init.routers ?? [] + this.started = false + this.components = components + + this.findProviders = components.metrics?.traceFunction('libp2p.contentRouting.findProviders', this.findProviders.bind(this), { + optionsIndex: 1, + getAttributesFromArgs: ([cid], attrs) => { + return { + ...attrs, + cid: cid.toString() + } + }, + getAttributesFromYieldedValue: (value, attrs: { providers?: string[] }) => { + return { + ...attrs, + providers: [...(Array.isArray(attrs.providers) ? attrs.providers : []), value.id.toString()] + } + } + }) ?? this.findProviders + this.provide = components.metrics?.traceFunction('libp2p.contentRouting.provide', this.provide.bind(this), { + optionsIndex: 1, + getAttributesFromArgs: ([cid], attrs) => { + return { + ...attrs, + cid: cid.toString() + } + } + }) ?? this.provide + this.cancelReprovide = components.metrics?.traceFunction('libp2p.contentRouting.cancelReprovide', this.cancelReprovide.bind(this), { + optionsIndex: 1, + getAttributesFromArgs: ([cid], attrs) => { + return { + ...attrs, + cid: cid.toString() + } + } + }) ?? this.cancelReprovide + this.put = components.metrics?.traceFunction('libp2p.contentRouting.put', this.put.bind(this), { + optionsIndex: 2, + getAttributesFromArgs: ([key]) => { + return { + key: uint8ArrayToString(key, 'base36') + } + } + }) ?? this.put + this.get = components.metrics?.traceFunction('libp2p.contentRouting.get', this.get.bind(this), { + optionsIndex: 1, + getAttributesFromArgs: ([key]) => { + return { + key: uint8ArrayToString(key, 'base36') + } + } + }) ?? this.get + } + + readonly [Symbol.toStringTag] = '@libp2p/content-routing' + + isStarted (): boolean { + return this.started + } + + async start (): Promise { + this.started = true + } + + async stop (): Promise { + this.started = false + } + + /** + * Iterates over all content routers in parallel to find providers of the given key + */ + async * findProviders (key: CID, options: RoutingOptions = {}): AsyncGenerator { + if (this.routers.length === 0) { + throw new NoContentRoutersError('No content routers available') + } + + const self = this + const seen = new PeerSet() + + for await (const peer of merge( + ...self.routers + .filter(router => router.findProviders instanceof Function) + .map(router => router.findProviders(key, options)) + )) { + // the peer was yielded by a content router without multiaddrs and we + // failed to load them + if (peer == null) { + continue + } + + // store the addresses for the peer if found + if (peer.multiaddrs.length > 0) { + await this.components.peerStore.merge(peer.id, { + multiaddrs: peer.multiaddrs + }, options) + } + + // deduplicate peers + if (seen.has(peer.id)) { + continue + } + + seen.add(peer.id) + + yield peer + } + } + + /** + * Iterates over all content routers in parallel to notify it is + * a provider of the given key + */ + async provide (key: CID, options: AbortOptions = {}): Promise { + if (this.routers.length === 0) { + throw new NoContentRoutersError('No content routers available') + } + + await Promise.all( + this.routers + .filter(router => router.provide instanceof Function) + .map(async (router) => { + await router.provide(key, options) + })) + } + + async cancelReprovide (key: CID, options: AbortOptions = {}): Promise { + if (this.routers.length === 0) { + throw new NoContentRoutersError('No content routers available') + } + + await Promise.all( + this.routers + .filter(router => router.cancelReprovide instanceof Function) + .map(async (router) => { + await router.cancelReprovide(key, options) + }) + ) + } + + /** + * Store the given key/value pair in the available content routings + */ + async put (key: Uint8Array, value: Uint8Array, options?: AbortOptions): Promise { + if (!this.isStarted()) { + throw new NotStartedError() + } + + await Promise.all( + this.routers + .filter(router => router.put instanceof Function) + .map(async (router) => { + await router.put(key, value, options) + }) + ) + } + + /** + * Get the value to the given key. + * Times out after 1 minute by default. + */ + async get (key: Uint8Array, options?: AbortOptions): Promise { + if (!this.isStarted()) { + throw new NotStartedError() + } + + return Promise.any( + this.routers + .filter(router => router.get instanceof Function) + .map(async (router) => { + return router.get(key, options) + }) + ) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/errors.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/errors.ts new file mode 100644 index 000000000..32d16486c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/errors.ts @@ -0,0 +1,123 @@ +export enum messages { + NOT_STARTED_YET = 'The libp2p node is not started yet', + NOT_FOUND = 'Not found' +} + +export class MissingServiceError extends Error { + constructor (message = 'Missing service') { + super(message) + this.name = 'MissingServiceError' + } +} + +export class UnmetServiceDependenciesError extends Error { + constructor (message = 'Unmet service dependencies') { + super(message) + this.name = 'UnmetServiceDependenciesError' + } +} + +export class NoContentRoutersError extends Error { + constructor (message = 'No content routers available') { + super(message) + this.name = 'NoContentRoutersError' + } +} + +export class NoPeerRoutersError extends Error { + constructor (message = 'No peer routers available') { + super(message) + this.name = 'NoPeerRoutersError' + } +} + +export class QueriedForSelfError extends Error { + constructor (message = 'Should not try to find self') { + super(message) + this.name = 'QueriedForSelfError' + } +} + +export class UnhandledProtocolError extends Error { + constructor (message = 'Unhandled protocol error') { + super(message) + this.name = 'UnhandledProtocolError' + } +} + +export class DuplicateProtocolHandlerError extends Error { + constructor (message = 'Duplicate protocol handler error') { + super(message) + this.name = 'DuplicateProtocolHandlerError' + } +} + +export class DialDeniedError extends Error { + constructor (message = 'Dial denied error') { + super(message) + this.name = 'DialDeniedError' + } +} + +export class UnsupportedListenAddressError extends Error { + constructor (message = 'No transport was configured to listen on this address') { + super(message) + this.name = 'UnsupportedListenAddressError' + } +} + +export class UnsupportedListenAddressesError extends Error { + constructor (message = 'Configured listen addresses could not be listened on') { + super(message) + this.name = 'UnsupportedListenAddressesError' + } +} + +export class NoValidAddressesError extends Error { + constructor (message = 'No valid addresses') { + super(message) + this.name = 'NoValidAddressesError' + } +} + +export class ConnectionInterceptedError extends Error { + constructor (message = 'Connection intercepted') { + super(message) + this.name = 'ConnectionInterceptedError' + } +} + +export class ConnectionDeniedError extends Error { + constructor (message = 'Connection denied') { + super(message) + this.name = 'ConnectionDeniedError' + } +} + +export class MuxerUnavailableError extends Error { + constructor (message = 'Stream is not multiplexed') { + super(message) + this.name = 'MuxerUnavailableError' + } +} + +export class EncryptionFailedError extends Error { + constructor (message = 'Encryption failed') { + super(message) + this.name = 'EncryptionFailedError' + } +} + +export class TransportUnavailableError extends Error { + constructor (message = 'Transport unavailable') { + super(message) + this.name = 'TransportUnavailableError' + } +} + +export class RecursionLimitError extends Error { + constructor (message = 'Max recursive depth reached') { + super(message) + this.name = 'RecursionLimitError' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/get-peer.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/get-peer.ts new file mode 100644 index 000000000..cda04f390 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/get-peer.ts @@ -0,0 +1,62 @@ +import { InvalidMultiaddrError, InvalidParametersError, isPeerId } from '@libp2p/interface' +import { peerIdFromString } from '@libp2p/peer-id' +import { isMultiaddr } from '@multiformats/multiaddr' +import { PEER_ID } from '@multiformats/multiaddr-matcher' +import type { PeerId } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +export interface PeerAddress { + peerId?: PeerId + multiaddrs: Multiaddr[] +} + +/** + * Extracts a PeerId and/or multiaddr from the passed PeerId or Multiaddr or an + * array of Multiaddrs + */ +export function getPeerAddress (peer: PeerId | Multiaddr | Multiaddr[]): PeerAddress { + if (isPeerId(peer)) { + return { peerId: peer, multiaddrs: [] } + } + + let multiaddrs = Array.isArray(peer) ? peer : [peer] + + let peerId: PeerId | undefined + + if (multiaddrs.length > 0) { + const peerIdStr = multiaddrs[0].getPeerId() + peerId = peerIdStr == null ? undefined : peerIdFromString(peerIdStr) + + // ensure PeerId is either not set or is consistent + multiaddrs.forEach(ma => { + if (!isMultiaddr(ma)) { + throw new InvalidMultiaddrError('Invalid multiaddr') + } + + const maPeerIdStr = ma.getPeerId() + + if (maPeerIdStr == null) { + if (peerId != null) { + throw new InvalidParametersError('Multiaddrs must all have the same peer id or have no peer id') + } + } else { + const maPeerId = peerIdFromString(maPeerIdStr) + + if (peerId?.equals(maPeerId) !== true) { + throw new InvalidParametersError('Multiaddrs must all have the same peer id or have no peer id') + } + } + }) + } + + // ignore any `/p2p/Qmfoo`-style addresses as we will include the peer id in + // the returned value of this function + multiaddrs = multiaddrs.filter(ma => { + return !PEER_ID.exactMatch(ma) + }) + + return { + peerId, + multiaddrs + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/index.ts new file mode 100644 index 000000000..777050ce3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/index.ts @@ -0,0 +1,234 @@ +/** + * @packageDocumentation + * + * Use the `createLibp2p` function to create a libp2p node. + * + * @example + * + * ```typescript + * import { createLibp2p } from 'libp2p' + * + * const node = await createLibp2p({ + * // ...other options + * }) + * ``` + */ + +import { generateKeyPair } from '@libp2p/crypto/keys' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { validateConfig } from './config.js' +import { Libp2p as Libp2pClass } from './libp2p.js' +import type { AddressManagerInit, AddressFilter } from './address-manager/index.js' +import type { Components } from './components.js' +import type { ConnectionManagerInit } from './connection-manager/index.js' +import type { ConnectionMonitorInit } from './connection-monitor.js' +import type { TransportManagerInit } from './transport-manager.js' +import type { Libp2p, ServiceMap, ComponentLogger, NodeInfo, ConnectionProtector, ConnectionEncrypter, ConnectionGater, ContentRouting, Metrics, PeerDiscovery, PeerRouting, StreamMuxerFactory, Transport, PrivateKey } from '@libp2p/interface' +import type { PersistentPeerStoreInit } from '@libp2p/peer-store' +import type { DNS } from '@multiformats/dns' +import type { Datastore } from 'interface-datastore' + +export type ServiceFactoryMap = { + [Property in keyof T]: (components: Components & T) => T[Property] +} + +export type { AddressManagerInit, AddressFilter } + +export { dnsaddrResolver } from './connection-manager/resolvers/index.ts' + +/** + * For Libp2p configurations and modules details read the [Configuration Document](https://github.com/libp2p/js-libp2p/tree/main/doc/CONFIGURATION.md). + */ +export interface Libp2pInit { + /** + * The private key is used in cryptographic operations and the Peer ID derived + * from it's corresponding public key is used to identify the node to other + * peers on the network. + * + * If this is not passed a new Ed25519 private key will be generated. + */ + privateKey?: PrivateKey + + /** + * Metadata about the node - implementation name, version number, etc + */ + nodeInfo?: Partial + + /** + * Addresses for transport listening and to advertise to the network + */ + addresses?: AddressManagerInit + + /** + * libp2p Connection Manager configuration + */ + connectionManager?: ConnectionManagerInit + + /** + * libp2p Connection Monitor configuration + */ + connectionMonitor?: ConnectionMonitorInit + + /** + * A connection gater can deny new connections based on user criteria + */ + connectionGater?: ConnectionGater + + /** + * libp2p transport manager configuration + */ + transportManager?: TransportManagerInit + + /** + * An optional datastore to persist peer information, DHT records, etc. + * + * An in-memory datastore will be used if one is not provided. + */ + datastore?: Datastore + + /** + * libp2p PeerStore configuration + */ + peerStore?: PersistentPeerStoreInit + + /** + * Transports are low-level communication channels + */ + transports?: Array<(components: Components) => Transport> + + /** + * Stream muxers allow the creation of many data streams over a single + * connection. + */ + streamMuxers?: Array<(components: Components) => StreamMuxerFactory> + + /** + * Connection encrypters ensure that data sent over connections cannot be + * eavesdropped on, and that the remote peer possesses the private key that + * corresponds to the public key that it's Peer ID is derived from. + */ + connectionEncrypters?: Array<(components: Components) => ConnectionEncrypter> + + /** + * Peer discovery mechanisms allow finding peers on the network + */ + peerDiscovery?: Array<(components: Components) => PeerDiscovery> + + /** + * Peer routers provide implementations for peer routing queries + */ + peerRouters?: Array<(components: Components) => PeerRouting> + + /** + * Content routers provide implementations for content routing queries + */ + contentRouters?: Array<(components: Components) => ContentRouting> + + /** + * A Metrics implementation can be supplied to collect metrics on this node + */ + metrics?(components: Components): Metrics + + /** + * A ConnectionProtector can be used to create a secure overlay on top of the network using pre-shared keys + */ + connectionProtector?(components: Components): ConnectionProtector + + /** + * Arbitrary libp2p modules + */ + services?: ServiceFactoryMap + + /** + * An optional logging implementation that can be used to write runtime logs. + * + * Set the `DEBUG` env var or the `debug` key on LocalStorage to see logs. + * + * @example + * + * Node.js: + * + * ```console + * $ DEBUG="*libp2p:*" node myscript.js + * ``` + * + * Browsers: + * + * ```TypeScript + * localStorage.setItem('debug', '*libp2p:*') + * ``` + */ + logger?: ComponentLogger + + /** + * An optional DNS resolver configuration. If omitted the default DNS resolver + * for the platform will be used which means `node:dns` on Node.js and + * DNS-JSON-over-HTTPS for browsers using Google and Cloudflare servers. + */ + dns?: DNS +} + +export type { Libp2p, ConnectionManagerInit, ConnectionMonitorInit, TransportManagerInit } + +export type Libp2pOptions = Libp2pInit & { start?: boolean } + +/** + * Returns a new instance of the Libp2p interface, generating a new PeerId + * if one is not passed as part of the options. + * + * The node will be started unless `start: false` is passed as an option. + * + * @example + * + * ```TypeScript + * import { createLibp2p } from 'libp2p' + * import { tcp } from '@libp2p/tcp' + * import { mplex } from '@libp2p/mplex' + * import { noise } from '@chainsafe/libp2p-noise' + * import { yamux } from '@chainsafe/libp2p-yamux' + * + * // specify options + * const options = { + * transports: [tcp()], + * streamMuxers: [yamux(), mplex()], + * connectionEncrypters: [noise()] + * } + * + * // create libp2p + * const libp2p = await createLibp2p(options) + * ``` + */ +export async function createLibp2p (options: Libp2pOptions = {}): Promise> { + options.privateKey ??= await generateKeyPair('Ed25519') + + const node = new Libp2pClass({ + ...await validateConfig(options), + peerId: peerIdFromPrivateKey(options.privateKey) + }) + + if (options.start !== false) { + await node.start() + } + + return node +} + +// a non-exhaustive list of methods found on the libp2p object +const LIBP2P_METHODS = ['dial', 'dialProtocol', 'hangUp', 'handle', 'unhandle', 'getMultiaddrs', 'getProtocols'] + +/** + * Returns true if the passed object is a libp2p node - this can be used for + * type guarding in TypeScript. + */ +export function isLibp2p (obj?: any): obj is Libp2p { + if (obj == null) { + return false + } + + if (obj instanceof Libp2pClass) { + return true + } + + // if these are all functions it's probably a libp2p object + return LIBP2P_METHODS.every(m => typeof obj[m] === 'function') +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/libp2p.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/libp2p.ts new file mode 100644 index 000000000..5dad2a052 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/libp2p.ts @@ -0,0 +1,426 @@ +import { publicKeyFromProtobuf } from '@libp2p/crypto/keys' +import { contentRoutingSymbol, peerDiscoverySymbol, peerRoutingSymbol, InvalidParametersError } from '@libp2p/interface' +import { defaultLogger } from '@libp2p/logger' +import { PeerSet } from '@libp2p/peer-collections' +import { peerIdFromString } from '@libp2p/peer-id' +import { persistentPeerStore } from '@libp2p/peer-store' +import { isMultiaddr } from '@multiformats/multiaddr' +import { MemoryDatastore } from 'datastore-core/memory' +import { TypedEventEmitter, setMaxListeners } from 'main-event' +import { concat as uint8ArrayConcat } from 'uint8arrays/concat' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { AddressManager } from './address-manager/index.js' +import { checkServiceDependencies, defaultComponents } from './components.js' +import { connectionGater } from './config/connection-gater.js' +import { DefaultConnectionManager } from './connection-manager/index.js' +import { ConnectionMonitor } from './connection-monitor.js' +import { CompoundContentRouting } from './content-routing.js' +import { DefaultPeerRouting } from './peer-routing.js' +import { RandomWalk } from './random-walk.js' +import { Registrar } from './registrar.js' +import { DefaultTransportManager } from './transport-manager.js' +import { Upgrader } from './upgrader.js' +import { userAgent } from './user-agent.js' +import * as pkg from './version.js' +import type { Components } from './components.js' +import type { Libp2p as Libp2pInterface, Libp2pInit } from './index.js' +import type { PeerRouting, ContentRouting, Libp2pEvents, PendingDial, ServiceMap, AbortOptions, ComponentLogger, Logger, Connection, NewStreamOptions, Stream, Metrics, PeerId, PeerInfo, PeerStore, Topology, Libp2pStatus, IsDialableOptions, DialOptions, PublicKey, Ed25519PeerId, Secp256k1PeerId, RSAPublicKey, RSAPeerId, URLPeerId, Ed25519PublicKey, Secp256k1PublicKey, StreamHandler, StreamHandlerOptions } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +export class Libp2p extends TypedEventEmitter implements Libp2pInterface { + public peerId: PeerId + public peerStore: PeerStore + public contentRouting: ContentRouting + public peerRouting: PeerRouting + public metrics?: Metrics + public services: T + public logger: ComponentLogger + public status: Libp2pStatus + + public components: Components & T + private readonly log: Logger + + // eslint-disable-next-line complexity + constructor (init: Libp2pInit & { peerId: PeerId }) { + super() + + this.status = 'stopped' + + // event bus - components can listen to this emitter to be notified of system events + // and also cause them to be emitted + const events = new TypedEventEmitter() + const originalDispatch = events.dispatchEvent.bind(events) + events.dispatchEvent = (evt: any) => { + const internalResult = originalDispatch(evt) + const externalResult = this.dispatchEvent( + new CustomEvent(evt.type, { detail: evt.detail }) + ) + + return internalResult || externalResult + } + + // This emitter gets listened to a lot + setMaxListeners(Infinity, events) + + this.peerId = init.peerId + this.logger = init.logger ?? defaultLogger() + this.log = this.logger.forComponent('libp2p') + // @ts-expect-error {} may not be of type T + this.services = {} + + const nodeInfoName = init.nodeInfo?.name ?? pkg.name + const nodeInfoVersion = init.nodeInfo?.version ?? pkg.version + + // @ts-expect-error defaultComponents is missing component types added later + const components = this.components = defaultComponents({ + peerId: init.peerId, + privateKey: init.privateKey, + nodeInfo: { + name: nodeInfoName, + version: nodeInfoVersion, + userAgent: init.nodeInfo?.userAgent ?? userAgent(nodeInfoName, nodeInfoVersion) + }, + logger: this.logger, + events, + datastore: init.datastore ?? new MemoryDatastore(), + connectionGater: connectionGater(init.connectionGater), + dns: init.dns + }) + + // Create Metrics + if (init.metrics != null) { + this.metrics = this.configureComponent('metrics', init.metrics(this.components)) + } + + this.peerStore = this.configureComponent('peerStore', persistentPeerStore(components, { + addressFilter: this.components.connectionGater.filterMultiaddrForPeer, + ...init.peerStore + })) + + components.events.addEventListener('peer:update', evt => { + // if there was no peer previously in the peer store this is a new peer + if (evt.detail.previous == null) { + const peerInfo: PeerInfo = { + id: evt.detail.peer.id, + multiaddrs: evt.detail.peer.addresses.map(a => a.multiaddr) + } + + components.events.safeDispatchEvent('peer:discovery', { detail: peerInfo }) + } + }) + + // Set up connection protector if configured + if (init.connectionProtector != null) { + this.configureComponent('connectionProtector', init.connectionProtector(components)) + } + + // Set up the Upgrader + this.components.upgrader = new Upgrader(this.components, { + connectionEncrypters: (init.connectionEncrypters ?? []).map((fn, index) => this.configureComponent(`connection-encryption-${index}`, fn(this.components))), + streamMuxers: (init.streamMuxers ?? []).map((fn, index) => this.configureComponent(`stream-muxers-${index}`, fn(this.components))), + inboundUpgradeTimeout: init.connectionManager?.inboundUpgradeTimeout, + inboundStreamProtocolNegotiationTimeout: init.connectionManager?.inboundStreamProtocolNegotiationTimeout ?? init.connectionManager?.protocolNegotiationTimeout, + outboundStreamProtocolNegotiationTimeout: init.connectionManager?.outboundStreamProtocolNegotiationTimeout ?? init.connectionManager?.protocolNegotiationTimeout + }) + + // Setup the transport manager + this.configureComponent('transportManager', new DefaultTransportManager(this.components, init.transportManager)) + + // Create the Connection Manager + this.configureComponent('connectionManager', new DefaultConnectionManager(this.components, init.connectionManager)) + + if (init.connectionMonitor?.enabled !== false) { + // Create the Connection Monitor if not disabled + this.configureComponent('connectionMonitor', new ConnectionMonitor(this.components, init.connectionMonitor)) + } + + // Create the Registrar + this.configureComponent('registrar', new Registrar(this.components)) + + // Addresses {listen, announce, noAnnounce} + this.configureComponent('addressManager', new AddressManager(this.components, init.addresses)) + + // Peer routers + const peerRouters: PeerRouting[] = (init.peerRouters ?? []).map((fn, index) => this.configureComponent(`peer-router-${index}`, fn(this.components))) + this.peerRouting = this.components.peerRouting = this.configureComponent('peerRouting', new DefaultPeerRouting(this.components, { + routers: peerRouters + })) + + // Content routers + const contentRouters: ContentRouting[] = (init.contentRouters ?? []).map((fn, index) => this.configureComponent(`content-router-${index}`, fn(this.components))) + this.contentRouting = this.components.contentRouting = this.configureComponent('contentRouting', new CompoundContentRouting(this.components, { + routers: contentRouters + })) + + // Random walk + this.configureComponent('randomWalk', new RandomWalk(this.components)) + + // Discovery modules + ;(init.peerDiscovery ?? []).forEach((fn, index) => { + const service = this.configureComponent(`peer-discovery-${index}`, fn(this.components)) + + service.addEventListener('peer', (evt) => { + this.#onDiscoveryPeer(evt) + }) + }) + + // Transport modules + init.transports?.forEach((fn, index) => { + this.components.transportManager.add(this.configureComponent(`transport-${index}`, fn(this.components))) + }) + + // User defined modules + if (init.services != null) { + for (const name of Object.keys(init.services)) { + const createService = init.services[name] + const service: any = createService(this.components) + + if (service == null) { + this.log.error('service factory %s returned null or undefined instance', name) + continue + } + + this.services[name as keyof T] = service + this.configureComponent(name, service) + + if (service[contentRoutingSymbol] != null) { + this.log('registering service %s for content routing', name) + contentRouters.push(service[contentRoutingSymbol]) + } + + if (service[peerRoutingSymbol] != null) { + this.log('registering service %s for peer routing', name) + peerRouters.push(service[peerRoutingSymbol]) + } + + if (service[peerDiscoverySymbol] != null) { + this.log('registering service %s for peer discovery', name) + service[peerDiscoverySymbol].addEventListener?.('peer', (evt: CustomEvent) => { + this.#onDiscoveryPeer(evt) + }) + } + } + } + + // Ensure all services have their required dependencies + checkServiceDependencies(components) + } + + private configureComponent (name: string, component: T): T { + if (component == null) { + this.log.error('component %s was null or undefined', name) + } + + // @ts-expect-error cannot assign props + this.components[name] = component + + return component + } + + /** + * Starts the libp2p node and all its subsystems + */ + async start (): Promise { + if (this.status !== 'stopped') { + return + } + + this.status = 'starting' + + this.log('libp2p is starting') + + try { + await this.components.beforeStart?.() + await this.components.start() + await this.components.afterStart?.() + + this.status = 'started' + this.safeDispatchEvent('start', { detail: this }) + this.log('libp2p has started') + } catch (err: any) { + this.log.error('An error occurred starting libp2p', err) + // set status to 'started' so this.stop() will stop any running components + this.status = 'started' + await this.stop() + throw err + } + } + + /** + * Stop the libp2p node by closing its listeners and open connections + */ + async stop (): Promise { + if (this.status !== 'started') { + return + } + + this.log('libp2p is stopping') + + this.status = 'stopping' + + await this.components.beforeStop?.() + await this.components.stop() + await this.components.afterStop?.() + + this.status = 'stopped' + this.safeDispatchEvent('stop', { detail: this }) + this.log('libp2p has stopped') + } + + getConnections (peerId?: PeerId): Connection[] { + return this.components.connectionManager.getConnections(peerId) + } + + getDialQueue (): PendingDial[] { + return this.components.connectionManager.getDialQueue() + } + + getPeers (): PeerId[] { + const peerSet = new PeerSet() + + for (const conn of this.components.connectionManager.getConnections()) { + peerSet.add(conn.remotePeer) + } + + return Array.from(peerSet) + } + + async dial (peer: PeerId | Multiaddr | Multiaddr[], options: DialOptions = {}): Promise { + return this.components.connectionManager.openConnection(peer, { + // ensure any userland dials take top priority in the queue + priority: 75, + ...options + }) + } + + async dialProtocol (peer: PeerId | Multiaddr | Multiaddr[], protocols: string | string[], options: NewStreamOptions = {}): Promise { + if (protocols == null) { + throw new InvalidParametersError('no protocols were provided to open a stream') + } + + protocols = Array.isArray(protocols) ? protocols : [protocols] + + if (protocols.length === 0) { + throw new InvalidParametersError('no protocols were provided to open a stream') + } + + const connection = await this.dial(peer, options) + + return connection.newStream(protocols, options) + } + + getMultiaddrs (): Multiaddr[] { + return this.components.addressManager.getAddresses() + } + + getProtocols (): string[] { + return this.components.registrar.getProtocols() + } + + async hangUp (peer: PeerId | Multiaddr, options: AbortOptions = {}): Promise { + if (isMultiaddr(peer)) { + peer = peerIdFromString(peer.getPeerId() ?? '') + } + + await this.components.connectionManager.closeConnections(peer, options) + } + + /** + * Get the public key for the given peer id + */ + async getPublicKey (peer: Ed25519PeerId, options?: AbortOptions): Promise + async getPublicKey (peer: Secp256k1PeerId, options?: AbortOptions): Promise + async getPublicKey (peer: RSAPeerId, options?: AbortOptions): Promise + async getPublicKey (peer: URLPeerId, options?: AbortOptions): Promise + async getPublicKey (peer: PeerId, options?: AbortOptions): Promise + async getPublicKey (peer: PeerId, options: AbortOptions = {}): Promise { + this.log('getPublicKey %p', peer) + + if (peer.publicKey != null) { + return peer.publicKey + } + + try { + const peerInfo = await this.peerStore.get(peer, options) + + if (peerInfo.id.publicKey != null) { + return peerInfo.id.publicKey + } + } catch (err: any) { + if (err.name !== 'NotFoundError') { + throw err + } + } + + const peerKey = uint8ArrayConcat([ + uint8ArrayFromString('/pk/'), + peer.toMultihash().bytes + ]) + + // search any available content routing methods + const bytes = await this.contentRouting.get(peerKey, options) + + // ensure the returned key is valid + const publicKey = publicKeyFromProtobuf(bytes) + + await this.peerStore.patch(peer, { + publicKey + }, options) + + return publicKey + } + + async handle (protocols: string | string[], handler: StreamHandler, options?: StreamHandlerOptions): Promise { + if (!Array.isArray(protocols)) { + protocols = [protocols] + } + + await Promise.all( + protocols.map(async protocol => { + await this.components.registrar.handle(protocol, handler, options) + }) + ) + } + + async unhandle (protocols: string[] | string, options?: AbortOptions): Promise { + if (!Array.isArray(protocols)) { + protocols = [protocols] + } + + await Promise.all( + protocols.map(async protocol => { + await this.components.registrar.unhandle(protocol, options) + }) + ) + } + + async register (protocol: string, topology: Topology, options?: AbortOptions): Promise { + return this.components.registrar.register(protocol, topology, options) + } + + unregister (id: string): void { + this.components.registrar.unregister(id) + } + + async isDialable (multiaddr: Multiaddr, options: IsDialableOptions = {}): Promise { + return this.components.connectionManager.isDialable(multiaddr, options) + } + + /** + * Called whenever peer discovery services emit `peer` events and adds peers + * to the peer store. + */ + #onDiscoveryPeer (evt: CustomEvent): void { + const { detail: peer } = evt + + if (peer.id.toString() === this.peerId.toString()) { + this.log.error('peer discovery mechanism discovered self') + return + } + + void this.components.peerStore.merge(peer.id, { + multiaddrs: peer.multiaddrs + }) + .catch(err => { this.log.error(err) }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/peer-routing.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/peer-routing.ts new file mode 100644 index 000000000..6cf435b86 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/peer-routing.ts @@ -0,0 +1,164 @@ +import { NotFoundError } from '@libp2p/interface' +import { createScalableCuckooFilter } from '@libp2p/utils' +import merge from 'it-merge' +import parallel from 'it-parallel' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { NoPeerRoutersError, QueriedForSelfError } from './errors.js' +import type { Logger, Metrics, PeerId, PeerInfo, PeerRouting, PeerStore, RoutingOptions } from '@libp2p/interface' +import type { ComponentLogger } from '@libp2p/logger' + +export interface PeerRoutingInit { + routers?: PeerRouting[] +} + +export interface DefaultPeerRoutingComponents { + peerId: PeerId + peerStore: PeerStore + logger: ComponentLogger + metrics?: Metrics +} + +export class DefaultPeerRouting implements PeerRouting { + private readonly log: Logger + private readonly peerId: PeerId + private readonly peerStore: PeerStore + private readonly routers: PeerRouting[] + + constructor (components: DefaultPeerRoutingComponents, init: PeerRoutingInit = {}) { + this.log = components.logger.forComponent('libp2p:peer-routing') + this.peerId = components.peerId + this.peerStore = components.peerStore + this.routers = init.routers ?? [] + + this.findPeer = components.metrics?.traceFunction('libp2p.peerRouting.findPeer', this.findPeer.bind(this), { + optionsIndex: 1, + getAttributesFromArgs: ([peer], attrs) => { + return { + ...attrs, + peer: peer.toString() + } + } + }) ?? this.findPeer + this.getClosestPeers = components.metrics?.traceFunction('libp2p.peerRouting.getClosestPeers', this.getClosestPeers.bind(this), { + optionsIndex: 1, + getAttributesFromArgs: ([key], attrs) => { + return { + ...attrs, + key: uint8ArrayToString(key, 'base36') + } + }, + getAttributesFromYieldedValue: (value, attrs: { peers?: string[] }) => { + return { + ...attrs, + peers: [...(Array.isArray(attrs.peers) ? attrs.peers : []), value.id.toString()] + } + } + }) ?? this.getClosestPeers + } + + readonly [Symbol.toStringTag] = '@libp2p/peer-routing' + + /** + * Iterates over all peer routers in parallel to find the given peer + */ + async findPeer (id: PeerId, options?: RoutingOptions): Promise { + if (this.routers.length === 0) { + throw new NoPeerRoutersError('No peer routers available') + } + + if (id.toString() === this.peerId.toString()) { + throw new QueriedForSelfError('Should not try to find self') + } + + const self = this + const source = merge( + ...this.routers + .filter(router => router.findPeer instanceof Function) + .map(router => (async function * () { + try { + yield await router.findPeer(id, options) + } catch (err) { + self.log.error(err) + } + })()) + ) + + for await (const peer of source) { + if (peer == null) { + continue + } + + // store the addresses for the peer if found + if (peer.multiaddrs.length > 0) { + await this.peerStore.merge(peer.id, { + multiaddrs: peer.multiaddrs + }, options) + } + + return peer + } + + throw new NotFoundError() + } + + /** + * Attempt to find the closest peers on the network to the given key + */ + async * getClosestPeers (key: Uint8Array, options: RoutingOptions = {}): AsyncGenerator { + if (this.routers.length === 0) { + throw new NoPeerRoutersError('No peer routers available') + } + + const self = this + const seen = createScalableCuckooFilter(1024) + + for await (const peer of parallel( + async function * () { + const source = merge( + ...self.routers + .filter(router => router.getClosestPeers instanceof Function) + .map(router => router.getClosestPeers(key, options)) + ) + + for await (let peer of source) { + yield async () => { + // find multiaddrs if they are missing + if (peer.multiaddrs.length === 0) { + try { + peer = await self.findPeer(peer.id, { + ...options, + useCache: false + }) + } catch (err) { + self.log.error('could not find peer multiaddrs', err) + return + } + } + + return peer + } + } + }() + )) { + if (peer == null) { + continue + } + + // store the addresses for the peer if found + if (peer.multiaddrs.length > 0) { + await this.peerStore.merge(peer.id, { + multiaddrs: peer.multiaddrs + }, options) + } + + // deduplicate peers + if (seen.has(peer.id.toMultihash().bytes)) { + continue + } + + seen.add(peer.id.toMultihash().bytes) + + yield peer + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/random-walk.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/random-walk.ts new file mode 100644 index 000000000..8cd6c4e09 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/random-walk.ts @@ -0,0 +1,155 @@ +import { randomBytes } from '@libp2p/crypto' +import { anySignal } from 'any-signal' +import { TypedEventEmitter, setMaxListeners } from 'main-event' +import pDefer from 'p-defer' +import { raceEvent } from 'race-event' +import { raceSignal } from 'race-signal' +import type { AbortOptions, ComponentLogger, Logger, PeerInfo, PeerRouting, Startable } from '@libp2p/interface' +import type { RandomWalk as RandomWalkInterface } from '@libp2p/interface-internal' +import type { DeferredPromise } from 'p-defer' + +export interface RandomWalkComponents { + peerRouting: PeerRouting + logger: ComponentLogger +} + +interface RandomWalkEvents { + 'walk:peer': CustomEvent + 'walk:error': CustomEvent +} + +export class RandomWalk extends TypedEventEmitter implements RandomWalkInterface, Startable { + private readonly peerRouting: PeerRouting + private readonly log: Logger + private walking: boolean + private walkers: number + private shutdownController: AbortController + private walkController?: AbortController + private needNext?: DeferredPromise + + constructor (components: RandomWalkComponents) { + super() + + this.log = components.logger.forComponent('libp2p:random-walk') + this.peerRouting = components.peerRouting + this.walkers = 0 + this.walking = false + + // stops any in-progress walks when the node is shut down + this.shutdownController = new AbortController() + setMaxListeners(Infinity, this.shutdownController.signal) + } + + readonly [Symbol.toStringTag] = '@libp2p/random-walk' + + start (): void { + this.shutdownController = new AbortController() + setMaxListeners(Infinity, this.shutdownController.signal) + } + + stop (): void { + this.shutdownController.abort() + } + + async * walk (options?: AbortOptions): AsyncGenerator { + if (!this.walking) { + // start the query that causes walk:peer events to be emitted + this.startWalk() + } + + this.walkers++ + const signal = anySignal([this.shutdownController.signal, options?.signal]) + setMaxListeners(Infinity, signal) + + try { + while (true) { + // if another consumer has paused the query, start it again + this.needNext?.resolve() + this.needNext = pDefer() + + // wait for a walk:peer or walk:error event + const event = await raceEvent>(this, 'walk:peer', signal, { + errorEvent: 'walk:error' + }) + + yield event.detail + } + } finally { + signal.clear() + this.walkers-- + + // stop the walk if no more consumers are interested + if (this.walkers === 0) { + this.walkController?.abort() + this.walkController = undefined + } + } + } + + private startWalk (): void { + this.walking = true + + // the signal for this controller will be aborted if no more random peers + // are required + this.walkController = new AbortController() + setMaxListeners(Infinity, this.walkController.signal) + + const signal = anySignal([this.walkController.signal, this.shutdownController.signal]) + setMaxListeners(Infinity, signal) + + const start = Date.now() + let found = 0 + + Promise.resolve().then(async () => { + this.log('start walk') + + // find peers until no more consumers are interested + while (this.walkers > 0) { + try { + const data = randomBytes(32) + let s = Date.now() + + for await (const peer of this.peerRouting.getClosestPeers(data, { signal })) { + if (signal.aborted) { + this.log('aborting walk') + } + + signal.throwIfAborted() + + this.log('found peer %p after %dms for %d walkers', peer.id, Date.now() - s, this.walkers) + found++ + this.safeDispatchEvent('walk:peer', { + detail: peer + }) + + // if we only have one consumer, pause the query until they request + // another random peer or they signal they are no longer interested + if (this.walkers === 1 && this.needNext != null) { + this.log('wait for need next') + await raceSignal(this.needNext.promise, signal) + } + + s = Date.now() + } + + this.log('walk iteration for %b and %d walkers finished, found %d peers', data, this.walkers, found) + } catch (err) { + this.log.error('random walk errored', err) + + this.safeDispatchEvent('walk:error', { + detail: err + }) + } + } + + this.log('no walkers left, ended walk') + }) + .catch(err => { + this.log.error('random walk errored', err) + }) + .finally(() => { + this.log('finished walk, found %d peers after %dms', found, Date.now() - start) + this.walking = false + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/registrar.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/registrar.ts new file mode 100644 index 000000000..61a86ea71 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/registrar.ts @@ -0,0 +1,264 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { mergeOptions, trackedMap } from '@libp2p/utils' +import { DuplicateProtocolHandlerError, UnhandledProtocolError } from './errors.js' +import type { IdentifyResult, Libp2pEvents, Logger, PeerUpdate, PeerId, PeerStore, Topology, StreamHandler, StreamHandlerRecord, StreamHandlerOptions, AbortOptions, Metrics } from '@libp2p/interface' +import type { Registrar as RegistrarInterface } from '@libp2p/interface-internal' +import type { ComponentLogger } from '@libp2p/logger' +import type { TypedEventTarget } from 'main-event' + +export const DEFAULT_MAX_INBOUND_STREAMS = 32 +export const DEFAULT_MAX_OUTBOUND_STREAMS = 64 + +export interface RegistrarComponents { + peerId: PeerId + peerStore: PeerStore + events: TypedEventTarget + logger: ComponentLogger + metrics?: Metrics +} + +/** + * Responsible for notifying registered protocols of events in the network. + */ +export class Registrar implements RegistrarInterface { + private readonly log: Logger + private readonly topologies: Map> + private readonly handlers: Map + private readonly components: RegistrarComponents + + constructor (components: RegistrarComponents) { + this.components = components + this.log = components.logger.forComponent('libp2p:registrar') + this.topologies = new Map() + components.metrics?.registerMetricGroup('libp2p_registrar_topologies', { + calculate: () => { + const output: Record = {} + + for (const [key, value] of this.topologies) { + output[key] = value.size + } + + return output + } + }) + this.handlers = trackedMap({ + name: 'libp2p_registrar_protocol_handlers', + metrics: components.metrics + }) + + this._onDisconnect = this._onDisconnect.bind(this) + this._onPeerUpdate = this._onPeerUpdate.bind(this) + this._onPeerIdentify = this._onPeerIdentify.bind(this) + + this.components.events.addEventListener('peer:disconnect', this._onDisconnect) + this.components.events.addEventListener('peer:update', this._onPeerUpdate) + this.components.events.addEventListener('peer:identify', this._onPeerIdentify) + } + + readonly [Symbol.toStringTag] = '@libp2p/registrar' + + getProtocols (): string[] { + return Array.from(new Set([ + ...this.handlers.keys() + ])).sort() + } + + getHandler (protocol: string): StreamHandlerRecord { + const handler = this.handlers.get(protocol) + + if (handler == null) { + throw new UnhandledProtocolError(`No handler registered for protocol ${protocol}`) + } + + return handler + } + + getTopologies (protocol: string): Topology[] { + const topologies = this.topologies.get(protocol) + + if (topologies == null) { + return [] + } + + return [ + ...topologies.values() + ] + } + + /** + * Registers the `handler` for each protocol + */ + async handle (protocol: string, handler: StreamHandler, opts?: StreamHandlerOptions): Promise { + if (this.handlers.has(protocol) && opts?.force !== true) { + throw new DuplicateProtocolHandlerError(`Handler already registered for protocol ${protocol}`) + } + + const options = mergeOptions.bind({ ignoreUndefined: true })({ + maxInboundStreams: DEFAULT_MAX_INBOUND_STREAMS, + maxOutboundStreams: DEFAULT_MAX_OUTBOUND_STREAMS + }, opts) + + this.handlers.set(protocol, { + handler, + options + }) + + // Add new protocol to self protocols in the peer store + await this.components.peerStore.merge(this.components.peerId, { + protocols: [protocol] + }, opts) + } + + /** + * Removes the handler for each protocol. The protocol + * will no longer be supported on streams. + */ + async unhandle (protocols: string | string[], options?: AbortOptions): Promise { + const protocolList = Array.isArray(protocols) ? protocols : [protocols] + + protocolList.forEach(protocol => { + this.handlers.delete(protocol) + }) + + // Update self protocols in the peer store + await this.components.peerStore.patch(this.components.peerId, { + protocols: this.getProtocols() + }, options) + } + + /** + * Register handlers for a set of multicodecs given + */ + async register (protocol: string, topology: Topology): Promise { + if (topology == null) { + throw new InvalidParametersError('invalid topology') + } + + // Create topology + const id = `${(Math.random() * 1e9).toString(36)}${Date.now()}` + + let topologies = this.topologies.get(protocol) + + if (topologies == null) { + topologies = new Map() + this.topologies.set(protocol, topologies) + } + + topologies.set(id, topology) + + return id + } + + /** + * Unregister topology + */ + unregister (id: string): void { + for (const [protocol, topologies] of this.topologies.entries()) { + if (topologies.has(id)) { + topologies.delete(id) + + if (topologies.size === 0) { + this.topologies.delete(protocol) + } + } + } + } + + /** + * Remove a disconnected peer from the record + */ + _onDisconnect (evt: CustomEvent): void { + const remotePeer = evt.detail + const options = { + signal: AbortSignal.timeout(5_000) + } + + void this.components.peerStore.get(remotePeer, options) + .then(peer => { + for (const protocol of peer.protocols) { + const topologies = this.topologies.get(protocol) + + if (topologies == null) { + // no topologies are interested in this protocol + continue + } + + for (const topology of topologies.values()) { + if (topology.filter?.has(remotePeer) === false) { + continue + } + + topology.filter?.remove(remotePeer) + topology.onDisconnect?.(remotePeer) + } + } + }) + .catch(err => { + if (err.name === 'NotFoundError') { + // peer has not completed identify so they are not in the peer store + return + } + + this.log.error('could not inform topologies of disconnecting peer %p', remotePeer, err) + }) + } + + /** + * When a peer is updated, if they have removed supported protocols notify any + * topologies interested in the removed protocols. + */ + _onPeerUpdate (evt: CustomEvent): void { + const { peer, previous } = evt.detail + const removed = (previous?.protocols ?? []).filter(protocol => !peer.protocols.includes(protocol)) + + for (const protocol of removed) { + const topologies = this.topologies.get(protocol) + + if (topologies == null) { + // no topologies are interested in this protocol + continue + } + + for (const topology of topologies.values()) { + if (topology.filter?.has(peer.id) === false) { + continue + } + + topology.filter?.remove(peer.id) + topology.onDisconnect?.(peer.id) + } + } + } + + /** + * After identify has completed and we have received the list of supported + * protocols, notify any topologies interested in those protocols. + */ + _onPeerIdentify (evt: CustomEvent): void { + const protocols = evt.detail.protocols + const connection = evt.detail.connection + const peerId = evt.detail.peerId + + for (const protocol of protocols) { + const topologies = this.topologies.get(protocol) + + if (topologies == null) { + // no topologies are interested in this protocol + continue + } + + for (const topology of topologies.values()) { + if (connection.limits != null && topology.notifyOnLimitedConnection !== true) { + continue + } + + if (topology.filter?.has(peerId) === true) { + continue + } + + topology.filter?.add(peerId) + topology.onConnect?.(peerId, connection) + } + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/transport-manager.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/transport-manager.ts new file mode 100644 index 000000000..919aa9663 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/transport-manager.ts @@ -0,0 +1,378 @@ +import { FaultTolerance, InvalidParametersError, NotStartedError } from '@libp2p/interface' +import { trackedMap } from '@libp2p/utils' +import { IP4, IP6 } from '@multiformats/multiaddr-matcher' +import { CustomProgressEvent } from 'progress-events' +import { TransportUnavailableError, UnsupportedListenAddressError, UnsupportedListenAddressesError } from './errors.js' +import type { Libp2pEvents, ComponentLogger, Logger, Connection, Metrics, Startable, Listener, Transport, Upgrader } from '@libp2p/interface' +import type { AddressManager, TransportManager, TransportManagerDialOptions } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { TypedEventTarget } from 'main-event' + +export interface TransportManagerInit { + faultTolerance?: FaultTolerance +} + +export interface DefaultTransportManagerComponents { + metrics?: Metrics + addressManager: AddressManager + upgrader: Upgrader + events: TypedEventTarget + logger: ComponentLogger +} + +interface IPStats { + success: number + attempts: number +} + +interface ListenStats { + errors: Map + ipv4: IPStats + ipv6: IPStats +} + +export class DefaultTransportManager implements TransportManager, Startable { + private readonly log: Logger + private readonly components: DefaultTransportManagerComponents + private readonly transports: Map + private readonly listeners: Map + private readonly faultTolerance: FaultTolerance + private started: boolean + + constructor (components: DefaultTransportManagerComponents, init: TransportManagerInit = {}) { + this.log = components.logger.forComponent('libp2p:transports') + this.components = components + this.started = false + this.transports = trackedMap({ + name: 'libp2p_transport_manager_transports', + metrics: this.components.metrics + }) + this.listeners = trackedMap({ + name: 'libp2p_transport_manager_listeners', + metrics: this.components.metrics + }) + this.faultTolerance = init.faultTolerance ?? FaultTolerance.FATAL_ALL + } + + readonly [Symbol.toStringTag] = '@libp2p/transport-manager' + + /** + * Adds a `Transport` to the manager + */ + add (transport: Transport): void { + const tag = transport[Symbol.toStringTag] + + if (tag == null) { + throw new InvalidParametersError('Transport must have a valid tag') + } + + if (this.transports.has(tag)) { + throw new InvalidParametersError(`There is already a transport with the tag ${tag}`) + } + + this.log('adding transport %s', tag) + + this.transports.set(tag, transport) + + if (!this.listeners.has(tag)) { + this.listeners.set(tag, []) + } + } + + isStarted (): boolean { + return this.started + } + + start (): void { + this.started = true + } + + async afterStart (): Promise { + // Listen on the provided transports for the provided addresses + const addrs = this.components.addressManager.getListenAddrs() + + await this.listen(addrs) + } + + /** + * Stops all listeners + */ + async stop (): Promise { + const tasks = [] + for (const [key, listeners] of this.listeners) { + this.log('closing listeners for %s', key) + while (listeners.length > 0) { + const listener = listeners.pop() + + if (listener == null) { + continue + } + + tasks.push(listener.close()) + } + } + + await Promise.all(tasks) + this.log('all listeners closed') + for (const key of this.listeners.keys()) { + this.listeners.set(key, []) + } + + this.started = false + } + + /** + * Dials the given Multiaddr over it's supported transport + */ + async dial (ma: Multiaddr, options?: TransportManagerDialOptions): Promise { + const transport = this.dialTransportForMultiaddr(ma) + + if (transport == null) { + throw new TransportUnavailableError(`No transport available for address ${String(ma)}`) + } + + options?.onProgress?.(new CustomProgressEvent('transport-manager:selected-transport', transport[Symbol.toStringTag])) + + // @ts-expect-error the transport has a typed onProgress option but we + // can't predict what transport implementation we selected so all we can + // do is pass the onProgress handler in and hope for the best + return transport.dial(ma, { + ...options, + upgrader: this.components.upgrader + }) + } + + /** + * Returns all Multiaddr's the listeners are using + */ + getAddrs (): Multiaddr[] { + let addrs: Multiaddr[] = [] + for (const listeners of this.listeners.values()) { + for (const listener of listeners) { + addrs = [...addrs, ...listener.getAddrs()] + } + } + return addrs + } + + /** + * Returns all the transports instances + */ + getTransports (): Transport[] { + return Array.of(...this.transports.values()) + } + + /** + * Returns all the listener instances + */ + getListeners (): Listener[] { + return Array.of(...this.listeners.values()).flat() + } + + /** + * Finds a transport that matches the given Multiaddr + */ + dialTransportForMultiaddr (ma: Multiaddr): Transport | undefined { + for (const transport of this.transports.values()) { + const addrs = transport.dialFilter([ma]) + + if (addrs.length > 0) { + return transport + } + } + } + + /** + * Finds a transport that matches the given Multiaddr + */ + listenTransportForMultiaddr (ma: Multiaddr): Transport | undefined { + for (const transport of this.transports.values()) { + const addrs = transport.listenFilter([ma]) + + if (addrs.length > 0) { + return transport + } + } + } + + /** + * Starts listeners for each listen Multiaddr + */ + async listen (addrs: Multiaddr[]): Promise { + if (!this.isStarted()) { + throw new NotStartedError('Not started') + } + + if (addrs == null || addrs.length === 0) { + this.log('no addresses were provided for listening, this node is dial only') + return + } + + // track IPv4/IPv6 results - if we succeed on IPv4 but all IPv6 attempts + // fail then we are probably on a network without IPv6 support + const listenStats: ListenStats = { + errors: new Map(), + ipv4: { + success: 0, + attempts: 0 + }, + ipv6: { + success: 0, + attempts: 0 + } + } + + addrs.forEach(ma => { + listenStats.errors.set(ma.toString(), new UnsupportedListenAddressError()) + }) + + const tasks: Array> = [] + + for (const [key, transport] of this.transports.entries()) { + const supportedAddrs = transport.listenFilter(addrs) + + // For each supported multiaddr, create a listener + for (const addr of supportedAddrs) { + this.log('creating listener for %s on %a', key, addr) + const listener = transport.createListener({ + upgrader: this.components.upgrader + }) + + let listeners: Listener[] = this.listeners.get(key) ?? [] + + if (listeners == null) { + listeners = [] + this.listeners.set(key, listeners) + } + + listeners.push(listener) + + // Track listen/close events + listener.addEventListener('listening', () => { + this.components.events.safeDispatchEvent('transport:listening', { + detail: listener + }) + }) + listener.addEventListener('close', () => { + const index = listeners.findIndex(l => l === listener) + + // remove the listener + listeners.splice(index, 1) + + this.components.events.safeDispatchEvent('transport:close', { + detail: listener + }) + }) + + // track IPv4/IPv6 support + if (IP4.matches(addr)) { + listenStats.ipv4.attempts++ + } else if (IP6.matches(addr)) { + listenStats.ipv6.attempts++ + } + + // We need to attempt to listen on everything + tasks.push( + listener.listen(addr) + .then(() => { + listenStats.errors.delete(addr.toString()) + + if (IP4.matches(addr)) { + listenStats.ipv4.success++ + } + + if (IP6.matches(addr)) { + listenStats.ipv6.success++ + } + }, (err) => { + this.log.error('transport %s could not listen on address %a - %e', key, addr, err) + listenStats.errors.set(addr.toString(), err) + throw err + }) + ) + } + } + + const results = await Promise.allSettled(tasks) + + // listening on all addresses, all good + if (results.length > 0 && results.every(res => res.status === 'fulfilled')) { + return + } + + // detect lack of IPv6 support on the current network - if we tried to + // listen on IPv4 and IPv6 addresses, and all IPv4 addresses succeeded but + // all IPv6 addresses fail, then we can assume there's no IPv6 here + if (this.ipv6Unsupported(listenStats)) { + this.log('all IPv4 addresses succeed but all IPv6 failed') + return + } + + if (this.faultTolerance === FaultTolerance.NO_FATAL) { + // ok to be dial-only + this.log('failed to listen on any address but fault tolerance allows this') + return + } + + // if a configured address was not able to be listened on, throw an error + throw new UnsupportedListenAddressesError(`Some configured addresses failed to be listened on, you may need to remove one or more listen addresses from your configuration or set \`transportManager.faultTolerance\` to NO_FATAL:\n${ + [...listenStats.errors.entries()].map(([addr, err]) => { + return ` + ${addr}: ${`${err.stack ?? err}`.split('\n').join('\n ')} +` + }).join('') + }`) + } + + private ipv6Unsupported (listenStats: ListenStats): boolean { + if (listenStats.ipv4.attempts === 0 || listenStats.ipv6.attempts === 0) { + return false + } + + const allIpv4Succeeded = listenStats.ipv4.attempts === listenStats.ipv4.success + const allIpv6Failed = listenStats.ipv6.success === 0 + + return allIpv4Succeeded && allIpv6Failed + } + + /** + * Removes the given transport from the manager. + * If a transport has any running listeners, they will be closed. + */ + async remove (key: string): Promise { + const listeners = this.listeners.get(key) ?? [] + this.log.trace('removing transport %s', key) + + // Close any running listeners + const tasks = [] + this.log.trace('closing listeners for %s', key) + while (listeners.length > 0) { + const listener = listeners.pop() + + if (listener == null) { + continue + } + + tasks.push(listener.close()) + } + await Promise.all(tasks) + + this.transports.delete(key) + this.listeners.delete(key) + } + + /** + * Removes all transports from the manager. + * If any listeners are running, they will be closed. + * + * @async + */ + async removeAll (): Promise { + const tasks = [] + for (const key of this.transports.keys()) { + tasks.push(this.remove(key)) + } + + await Promise.all(tasks) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/upgrader.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/upgrader.ts new file mode 100644 index 000000000..5516ae5df --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/upgrader.ts @@ -0,0 +1,484 @@ +import { InvalidMultiaddrError, InvalidPeerIdError } from '@libp2p/interface' +import * as mss from '@libp2p/multistream-select' +import { peerIdFromString } from '@libp2p/peer-id' +import { trackedMap } from '@libp2p/utils' +import { anySignal } from 'any-signal' +import { setMaxListeners } from 'main-event' +import { CustomProgressEvent } from 'progress-events' +import { raceSignal } from 'race-signal' +import { PROTOCOL_NEGOTIATION_TIMEOUT, INBOUND_UPGRADE_TIMEOUT } from './connection-manager/constants.js' +import { createConnection } from './connection.js' +import { ConnectionDeniedError, ConnectionInterceptedError, EncryptionFailedError, MuxerUnavailableError } from './errors.js' +import type { Libp2pEvents, AbortOptions, ComponentLogger, MultiaddrConnection, Connection, ConnectionProtector, ConnectionEncrypter, ConnectionGater, Metrics, PeerId, PeerStore, StreamMuxerFactory, Upgrader as UpgraderInterface, UpgraderOptions, ConnectionLimits, CounterGroup, ClearableSignal, MessageStream, SecuredConnection, StreamMuxer, UpgraderWithoutEncryptionOptions, SecureConnectionOptions } from '@libp2p/interface' +import type { ConnectionManager, Registrar } from '@libp2p/interface-internal' +import type { TypedEventTarget } from 'main-event' +import { Uint8ArrayList } from 'uint8arraylist' + +interface CreateConnectionOptions { + id: string + cryptoProtocol: string + direction: 'inbound' | 'outbound' + + /** + * The raw underlying connection + */ + maConn: MultiaddrConnection + + /** + * The encrypted, multiplexed connection + */ + stream: MessageStream + + remotePeer: PeerId + muxer?: StreamMuxer + limits?: ConnectionLimits +} + +export interface UpgraderInit { + connectionEncrypters: ConnectionEncrypter[] + streamMuxers: StreamMuxerFactory[] + + /** + * An amount of ms by which an inbound connection upgrade must complete + * + * @default 3000 + */ + inboundUpgradeTimeout?: number + + /** + * When a new incoming stream is opened on a multiplexed connection, protocol + * negotiation on that stream must complete within this many ms + * + * @default 2000 + */ + inboundStreamProtocolNegotiationTimeout?: number + + /** + * When a new incoming stream is opened on a multiplexed connection, protocol + * negotiation on that stream must complete within this many ms + * + * @default 2000 + */ + outboundStreamProtocolNegotiationTimeout?: number +} + +export interface UpgraderComponents { + peerId: PeerId + metrics?: Metrics + connectionManager: ConnectionManager + connectionGater: ConnectionGater + connectionProtector?: ConnectionProtector + registrar: Registrar + peerStore: PeerStore + events: TypedEventTarget + logger: ComponentLogger +} + +interface EncryptedConnection extends SecuredConnection { + protocol: string + earlyData?: Uint8ArrayList +} + +interface StreamMuxerNegotiationOptions extends AbortOptions { + earlyData?: Uint8ArrayList +} + +type ConnectionDeniedType = keyof Pick + +export class Upgrader implements UpgraderInterface { + private readonly components: UpgraderComponents + private readonly connectionEncrypters: Map + private readonly streamMuxers: Map + private readonly inboundUpgradeTimeout: number + private readonly inboundStreamProtocolNegotiationTimeout: number + private readonly outboundStreamProtocolNegotiationTimeout: number + private readonly events: TypedEventTarget + private readonly metrics: { + dials?: CounterGroup<'inbound' | 'outbound'> + errors?: CounterGroup<'inbound' | 'outbound'> + inboundErrors?: CounterGroup + outboundErrors?: CounterGroup + } + + constructor (components: UpgraderComponents, init: UpgraderInit) { + this.components = components + this.connectionEncrypters = trackedMap({ + name: 'libp2p_upgrader_connection_encrypters', + metrics: this.components.metrics + }) + + init.connectionEncrypters.forEach(encrypter => { + this.connectionEncrypters.set(encrypter.protocol, encrypter) + }) + + this.streamMuxers = trackedMap({ + name: 'libp2p_upgrader_stream_multiplexers', + metrics: this.components.metrics + }) + + init.streamMuxers.forEach(muxer => { + this.streamMuxers.set(muxer.protocol, muxer) + }) + + this.inboundUpgradeTimeout = init.inboundUpgradeTimeout ?? INBOUND_UPGRADE_TIMEOUT + this.inboundStreamProtocolNegotiationTimeout = init.inboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT + this.outboundStreamProtocolNegotiationTimeout = init.outboundStreamProtocolNegotiationTimeout ?? PROTOCOL_NEGOTIATION_TIMEOUT + this.events = components.events + this.metrics = { + dials: components.metrics?.registerCounterGroup('libp2p_connection_manager_dials_total'), + errors: components.metrics?.registerCounterGroup('libp2p_connection_manager_dial_errors_total'), + inboundErrors: components.metrics?.registerCounterGroup('libp2p_connection_manager_dials_inbound_errors_total'), + outboundErrors: components.metrics?.registerCounterGroup('libp2p_connection_manager_dials_outbound_errors_total') + } + } + + readonly [Symbol.toStringTag] = '@libp2p/upgrader' + + async shouldBlockConnection (connectionType: 'denyInboundConnection', maConn: MultiaddrConnection): Promise + async shouldBlockConnection (connectionType: ConnectionDeniedType, remotePeer: PeerId, maConn: MultiaddrConnection): Promise + async shouldBlockConnection (method: ConnectionDeniedType | 'denyInboundConnection', ...args: any[]): Promise { + const denyOperation: any = this.components.connectionGater[method] + + if (denyOperation == null) { + return + } + + const result = await denyOperation.apply(this.components.connectionGater, args) + + if (result === true) { + throw new ConnectionInterceptedError(`The multiaddr connection is blocked by gater.${method}`) + } + } + + createInboundAbortSignal (signal: AbortSignal): ClearableSignal { + const output = anySignal([ + AbortSignal.timeout(this.inboundUpgradeTimeout), + signal + ]) + setMaxListeners(Infinity, output) + + return output + } + + /** + * Upgrades an inbound connection + */ + async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise + async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise + async upgradeInbound (maConn: MultiaddrConnection, opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise { + let accepted = false + + // always apply upgrade timeout for incoming upgrades + const signal = this.createInboundAbortSignal(opts.signal) + + try { + this.metrics.dials?.increment({ + inbound: true + }) + + accepted = this.components.connectionManager.acceptIncomingConnection(maConn) + + if (!accepted) { + throw new ConnectionDeniedError('Connection denied') + } + + await raceSignal(this.shouldBlockConnection('denyInboundConnection', maConn), signal) + + await this._performUpgrade(maConn, 'inbound', { + ...opts, + signal + }) + } catch (err: any) { + this.metrics.errors?.increment({ + inbound: true + }) + this.metrics.inboundErrors?.increment({ + [err.name ?? 'Error']: true + }) + + throw err + } finally { + signal.clear() + + if (accepted) { + this.components.connectionManager.afterUpgradeInbound() + } + } + } + + /** + * Upgrades an outbound connection + */ + async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions): Promise + async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderWithoutEncryptionOptions): Promise + async upgradeOutbound (maConn: MultiaddrConnection, opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise { + try { + this.metrics.dials?.increment({ + outbound: true + }) + + const idStr = maConn.remoteAddr.getPeerId() + let remotePeerId: PeerId | undefined + + if (idStr != null) { + remotePeerId = peerIdFromString(idStr) + await raceSignal(this.shouldBlockConnection('denyOutboundConnection', remotePeerId, maConn), opts.signal) + } + + let direction: 'inbound' | 'outbound' = 'outbound' + + // act as the multistream-select server if we are not to be the initiator + if (opts.initiator === false) { + direction = 'inbound' + } + + return await this._performUpgrade(maConn, direction, opts) + } catch (err: any) { + this.metrics.errors?.increment({ + outbound: true + }) + this.metrics.outboundErrors?.increment({ + [err.name ?? 'Error']: true + }) + + throw err + } + } + + private async _performUpgrade (maConn: MultiaddrConnection, direction: 'inbound' | 'outbound', opts: UpgraderOptions | UpgraderWithoutEncryptionOptions): Promise { + let stream: MessageStream = maConn + let remotePeer: PeerId + let muxerFactory: StreamMuxerFactory | undefined + let muxer: StreamMuxer | undefined + let cryptoProtocol + let earlyData: Uint8ArrayList | undefined + + const id = `${(parseInt(String(Math.random() * 1e9))).toString(36)}${Date.now()}` + maConn.log = maConn.log.newScope(`${direction}:${id}`) + + this.components.metrics?.trackMultiaddrConnection(maConn) + + maConn.log.trace('starting the %s connection upgrade', direction) + + // Protect + if (opts?.skipProtection !== true) { + const protector = this.components.connectionProtector + + if (protector != null) { + maConn.log('protecting the %s connection', direction) + stream = await protector.protect(stream, opts) + } + } + + try { + // Encrypt the connection + if (isEncryptionSkipped(opts)) { + if (opts.remotePeer == null) { + throw new InvalidMultiaddrError(`${direction} connection that skipped encryption must have a peer id`) + } + + cryptoProtocol = 'native' + remotePeer = opts.remotePeer + } else { + opts?.onProgress?.(new CustomProgressEvent(`upgrader:encrypt-${direction}-connection`)); + + ({ + connection: stream, + remotePeer, + protocol: cryptoProtocol, + streamMuxer: muxerFactory, + earlyData + } = await (direction === 'inbound' + ? this._encryptInbound(stream, opts) + : this._encryptOutbound(stream, opts) + )) + } + + // this can happen if we dial a multiaddr without a peer id, we only find + // out the identity of the remote after the connection is encrypted + if (remotePeer.equals(this.components.peerId)) { + const err = new InvalidPeerIdError('Can not dial self') + maConn.abort(err) + throw err + } + + await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundEncryptedConnection' : 'denyOutboundEncryptedConnection', remotePeer, maConn) + + if (opts?.muxerFactory != null) { + muxerFactory = opts.muxerFactory + } else if (muxerFactory == null && this.streamMuxers.size > 0) { + opts?.onProgress?.(new CustomProgressEvent(`upgrader:multiplex-${direction}-connection`)) + + // Multiplex the connection + muxerFactory = await (direction === 'inbound' + ? this._multiplexInbound(stream, this.streamMuxers, opts) + : this._multiplexOutbound(stream, this.streamMuxers, opts)) + } + } catch (err: any) { + maConn.log.error('failed to upgrade %s connection %s %a - %e', direction, direction === 'inbound' ? 'from' : 'to', maConn.remoteAddr, err) + throw err + } + + await this.shouldBlockConnection(direction === 'inbound' ? 'denyInboundUpgradedConnection' : 'denyOutboundUpgradedConnection', remotePeer, maConn) + + // create the connection muxer if one is configured + if (muxerFactory != null) { + muxer = muxerFactory.createStreamMuxer(stream) + } + + const conn = this._createConnection({ + id, + cryptoProtocol, + direction, + maConn, + stream, + muxer, + remotePeer, + limits: opts?.limits + }) + + conn.log('successfully upgraded connection') + + return conn + } + + /** + * A convenience method for generating a new `Connection` + */ + _createConnection (opts: CreateConnectionOptions): Connection { + // Create the connection + const connection = createConnection(this.components, { + ...opts, + outboundStreamProtocolNegotiationTimeout: this.outboundStreamProtocolNegotiationTimeout, + inboundStreamProtocolNegotiationTimeout: this.inboundStreamProtocolNegotiationTimeout + }) + + connection.addEventListener('close', () => { + this.events.safeDispatchEvent('connection:close', { + detail: connection + }) + }) + + this.events.safeDispatchEvent('connection:open', { + detail: connection + }) + + opts.maConn.timeline.upgraded = Date.now() + + return connection + } + + /** + * Attempts to encrypt the incoming `connection` with the provided `cryptos` + */ + async _encryptInbound (connection: MessageStream, options?: AbortOptions): Promise { + const protocols = Array.from(this.connectionEncrypters.keys()) + + try { + const protocol = await mss.handle(connection, protocols, options) + const encrypter = this.connectionEncrypters.get(protocol) + + if (encrypter == null) { + throw new EncryptionFailedError(`no crypto module found for ${protocol}`) + } + + connection.log('encrypting inbound connection using %s', protocol) + + return { + ...await encrypter.secureInbound(connection, options), + protocol + } + } catch (err: any) { + throw new EncryptionFailedError(err.message) + } + } + + /** + * Attempts to encrypt the given `connection` with the provided connection encrypters. + * The first `ConnectionEncrypter` module to succeed will be used + */ + async _encryptOutbound (connection: MessageStream, options?: AbortOptions): Promise { + const protocols = Array.from(this.connectionEncrypters.keys()) + + try { + connection.log.trace('selecting encrypter from %s', protocols) + + const protocol = await mss.select(connection, protocols, options) + const encrypter = this.connectionEncrypters.get(protocol) + + if (encrypter == null) { + throw new EncryptionFailedError(`no crypto module found for ${protocol}`) + } + + connection.log('encrypting outbound connection using %s', protocol) + + return { + ...await encrypter.secureOutbound(connection, options), + protocol + } + } catch (err: any) { + throw new EncryptionFailedError(err.message) + } + } + + /** + * Selects one of the given muxers via multistream-select. That + * muxer will be used for all future streams on the connection. + */ + async _multiplexOutbound (maConn: MessageStream, muxers: Map, options: StreamMuxerNegotiationOptions): Promise { + const protocols = Array.from(muxers.keys()) + maConn.log('outbound selecting muxer %s', protocols) + + try { + maConn.log.trace('selecting stream muxer from %s', protocols) + const protocol = await mss.select(maConn, protocols, options) + const muxerFactory = muxers.get(protocol) + + if (muxerFactory == null) { + throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`) + } + + maConn.log('selected %s as muxer protocol', protocol) + return muxerFactory + } catch (err: any) { + maConn.log.error('error multiplexing outbound connection', err) + throw new MuxerUnavailableError(String(err)) + } + } + + /** + * Registers support for one of the given muxers via multistream-select. The + * selected muxer will be used for all future streams on the connection. + */ + async _multiplexInbound (maConn: MessageStream, muxers: Map, options: StreamMuxerNegotiationOptions): Promise { + const protocols = Array.from(muxers.keys()) + maConn.log('inbound handling muxers %s', protocols) + try { + maConn.log.trace('selecting stream muxer from %s', protocols) + const protocol = await mss.handle(maConn, protocols, options) + const muxerFactory = muxers.get(protocol) + + if (muxerFactory == null) { + throw new MuxerUnavailableError(`No muxer configured for protocol "${protocol}"`) + } + + maConn.log('selected %s as muxer protocol', protocol) + return muxerFactory + } catch (err: any) { + maConn.log.error('error multiplexing inbound connection', err) + throw err + } + } + + getConnectionEncrypters (): Map> { + return this.connectionEncrypters + } + + getStreamMuxers (): Map { + return this.streamMuxers + } +} + +function isEncryptionSkipped (opts?: any): opts is UpgraderWithoutEncryptionOptions { + return opts.skipEncryption === true +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.browser.ts new file mode 100644 index 000000000..7222c465a --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.browser.ts @@ -0,0 +1,5 @@ +import * as pkg from './version.js' + +export function userAgent (name?: string, version?: string): string { + return `${name ?? pkg.name}/${version ?? pkg.version} browser/${globalThis.navigator.userAgent}` +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.react-native.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.react-native.ts new file mode 100644 index 000000000..168970bfa --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.react-native.ts @@ -0,0 +1,6 @@ +import { Platform } from 'react-native' +import * as pkg from './version.js' + +export function userAgent (name?: string, version?: string): string { + return `${name ?? pkg.name}/${version ?? pkg.version} react-native/${Platform.OS}-${`${Platform.Version}`.replaceAll('v', '')}` +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.ts new file mode 100644 index 000000000..9d68ecf0f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/user-agent.ts @@ -0,0 +1,24 @@ +import process from 'node:process' +import * as pkg from './version.js' + +export function userAgent (name?: string, version?: string): string { + let platform = 'node' + let platformVersion = process.versions.node + + if (process.versions.deno != null) { + platform = 'deno' + platformVersion = process.versions.deno + } + + if (process.versions.bun != null) { + platform = 'bun' + platformVersion = process.versions.bun + } + + if (process.versions.electron != null) { + platform = 'electron' + platformVersion = process.versions.electron + } + + return `${name ?? pkg.name}/${version ?? pkg.version} ${platform}/${platformVersion.replaceAll('v', '')}` +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/utils.ts new file mode 100644 index 000000000..598ed3377 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/utils.ts @@ -0,0 +1,31 @@ +import type { MessageStream } from '@libp2p/interface' + +export function redirect (channelA: MessageStream, channelB: MessageStream): void { + channelA.addEventListener('message', (evt) => { + const sendMore = channelB.send(evt.data) + + if (sendMore === false) { + channelA.pause() + + channelA.addEventListener('drain', () => { + channelA.resume() + }, { + once: true + }) + } + }) + + channelB.addEventListener('message', (evt) => { + const sendMore = channelA.send(evt.data) + + if (sendMore === false) { + channelB.pause() + + channelB.addEventListener('drain', () => { + channelB.resume() + }, { + once: true + }) + } + }) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/version.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/version.ts new file mode 100644 index 000000000..238af7706 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/src/version.ts @@ -0,0 +1,2 @@ +export const version = '0.0.0' +export const name = 'js-libp2p' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/typedoc.json new file mode 100644 index 000000000..8394fbb4c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/libp2p/typedoc.json @@ -0,0 +1,8 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts", + "./src/user-agent.ts", + "./src/version.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/README.md new file mode 100644 index 000000000..a0dc2e07d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/README.md @@ -0,0 +1,84 @@ +# @libp2p/logger + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> A logging component for use in js-libp2p modules + +# About + + + +A logger for libp2p based on [weald](https://www.npmjs.com/package/weald), a TypeScript port of the venerable [debug](https://www.npmjs.com/package/debug) module. + +## Example + +```TypeScript +import { logger } from '@libp2p/logger' + +const log = logger('libp2p:my:component:name') + +try { + // an operation + log('something happened: %s', 'it was ok') +} catch (err) { + log.error('something bad happened: %o', err) +} + +log('with this peer: %p', {}) +log('and this base58btc: %b', Uint8Array.from([0, 1, 2, 3])) +log('and this base32: %t', Uint8Array.from([4, 5, 6, 7])) +``` + +```console +$ DEBUG=libp2p:* node index.js +something happened: it was ok +something bad happened: +with this peer: 12D3Foo +with this base58btc: Qmfoo +with this base32: bafyfoo +``` + +# Install + +```console +$ npm i @libp2p/logger +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/logger/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/logger/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/package.json new file mode 100644 index 000000000..c8c4fd7ef --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/package.json @@ -0,0 +1,63 @@ +{ + "name": "@libp2p/logger", + "version": "5.1.21", + "description": "A logging component for use in js-libp2p modules", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/logger#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "IPFS" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main" + }, + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@multiformats/multiaddr": "^12.4.4", + "interface-datastore": "^8.3.1", + "multiformats": "^13.3.6", + "weald": "^1.0.4" + }, + "browser": { + "./dist/src/debug/node.js": "./dist/src/debug/browser.js" + }, + "react-native": { + "./dist/src/debug/node.js": "./dist/src/debug/browser.js" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/src/index.ts new file mode 100644 index 000000000..356b88fca --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/src/index.ts @@ -0,0 +1,228 @@ +/** + * @packageDocumentation + * + * A logger for libp2p based on [weald](https://www.npmjs.com/package/weald), a TypeScript port of the venerable [debug](https://www.npmjs.com/package/debug) module. + * + * @example + * + * ```TypeScript + * import { logger } from '@libp2p/logger' + * + * const log = logger('libp2p:my:component:name') + * + * try { + * // an operation + * log('something happened: %s', 'it was ok') + * } catch (err) { + * log.error('something bad happened: %o', err) + * } + * + * log('with this peer: %p', {}) + * log('and this base58btc: %b', Uint8Array.from([0, 1, 2, 3])) + * log('and this base32: %t', Uint8Array.from([4, 5, 6, 7])) + * ``` + * + * ```console + * $ DEBUG=libp2p:* node index.js + * something happened: it was ok + * something bad happened: + * with this peer: 12D3Foo + * with this base58btc: Qmfoo + * with this base32: bafyfoo + * ``` + */ + +import { base32 } from 'multiformats/bases/base32' +import { base58btc } from 'multiformats/bases/base58' +import { base64 } from 'multiformats/bases/base64' +import debug from 'weald' +import { truncatePeerId } from './utils.js' +import type { PeerId, Logger, ComponentLogger } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Key } from 'interface-datastore' +import type { CID } from 'multiformats/cid' + +// Add a formatter for converting to a base58 string +debug.formatters.b = (v?: Uint8Array): string => { + return v == null ? 'undefined' : base58btc.baseEncode(v) +} + +// Add a formatter for converting to a base32 string +debug.formatters.t = (v?: Uint8Array): string => { + return v == null ? 'undefined' : base32.baseEncode(v) +} + +// Add a formatter for converting to a base64 string +debug.formatters.m = (v?: Uint8Array): string => { + return v == null ? 'undefined' : base64.baseEncode(v) +} + +// Add a formatter for stringifying peer ids +debug.formatters.p = (v?: PeerId): string => { + return v == null ? 'undefined' : v.toString() +} + +// Add a formatter for stringifying CIDs +debug.formatters.c = (v?: CID): string => { + return v == null ? 'undefined' : v.toString() +} + +// Add a formatter for stringifying Datastore keys +debug.formatters.k = (v: Key): string => { + return v == null ? 'undefined' : v.toString() +} + +// Add a formatter for stringifying Multiaddrs +debug.formatters.a = (v?: Multiaddr): string => { + return v == null ? 'undefined' : v.toString() +} + +// Add a formatter for stringifying Errors +debug.formatters.e = (v?: Error): string => { + return v == null ? 'undefined' : notEmpty(v.stack) ?? notEmpty(v.message) ?? v.toString() +} + +export type { Logger, ComponentLogger } + +function createDisabledLogger (namespace: string): debug.Debugger { + const logger = (): void => {} + logger.enabled = false + logger.color = '' + logger.diff = 0 + logger.log = (): void => {} + logger.namespace = namespace + logger.destroy = () => true + logger.extend = () => logger + + return logger +} + +export interface PeerLoggerOptions { + prefixLength: number + suffixLength: number +} + +/** + * Create a component logger that will prefix any log messages with a truncated + * peer id. + * + * @example + * + * ```TypeScript + * import { peerLogger } from '@libp2p/logger' + * import { peerIdFromString } from '@libp2p/peer-id' + * + * const peerId = peerIdFromString('12D3FooBar') + * const logger = peerLogger(peerId) + * + * const log = logger.forComponent('my-component') + * log.info('hello world') + * // logs "12…oBar:my-component hello world" + * ``` + */ +export function peerLogger (peerId: PeerId, options: Partial = {}): ComponentLogger { + return prefixLogger(truncatePeerId(peerId, options)) +} + +/** + * Create a component logger that will prefix any log messages with the passed + * string. + * + * @example + * + * ```TypeScript + * import { prefixLogger } from '@libp2p/logger' + * + * const logger = prefixLogger('my-node') + * + * const log = logger.forComponent('my-component') + * log.info('hello world') + * // logs "my-node:my-component hello world" + * ``` + */ +export function prefixLogger (prefix: string): ComponentLogger { + return { + forComponent (name: string) { + return logger(`${prefix}:${name}`) + } + } +} + +/** + * Create a component logger + * + * @example + * + * ```TypeScript + * import { defaultLogger } from '@libp2p/logger' + * import { peerIdFromString } from '@libp2p/peer-id' + * + * const logger = defaultLogger() + * + * const log = logger.forComponent('my-component') + * log.info('hello world') + * // logs "my-component hello world" + * ``` + */ +export function defaultLogger (): ComponentLogger { + return { + forComponent (name: string) { + return logger(name) + } + } +} + +/** + * Creates a logger for the passed component name. + * + * @example + * + * ```TypeScript + * import { logger } from '@libp2p/logger' + * + * const log = logger('my-component') + * log.info('hello world') + * // logs "my-component hello world" + * ``` + */ +export function logger (name: string): Logger { + // trace logging is a no-op by default + let trace: debug.Debugger = createDisabledLogger(`${name}:trace`) + + // look at all the debug names and see if trace logging has explicitly been enabled + if (debug.enabled(`${name}:trace`) && debug.names.map((r: any) => r.toString()).find((n: string) => n.includes(':trace')) != null) { + trace = debug(`${name}:trace`) + } + + return Object.assign(debug(name), { + error: debug(`${name}:error`), + trace, + newScope: (scope: string) => logger(`${name}:${scope}`) + }) +} + +export function disable (): void { + debug.disable() +} + +export function enable (namespaces: string): void { + debug.enable(namespaces) +} + +export function enabled (namespaces: string): boolean { + return debug.enabled(namespaces) +} + +function notEmpty (str?: string): string | undefined { + if (str == null) { + return + } + + str = str.trim() + + if (str.length === 0) { + return + } + + return str +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/src/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/src/utils.ts new file mode 100644 index 000000000..ac6b5d9a6 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/src/utils.ts @@ -0,0 +1,10 @@ +import type { PeerLoggerOptions } from './index.js' +import type { PeerId } from '@libp2p/interface' + +export function truncatePeerId (peerId: PeerId, options: Partial = {}): string { + const prefixLength = options.prefixLength ?? 2 + const suffixLength = options.suffixLength ?? 4 + + const peerIdString = peerId.toString() + return `${peerIdString.substring(0, prefixLength)}…${peerIdString.substring(peerIdString.length, peerIdString.length - suffixLength)}` +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/logger/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/README.md new file mode 100644 index 000000000..c0c2d64db --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/README.md @@ -0,0 +1,72 @@ +# @libp2p/multistream-select + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> JavaScript implementation of multistream-select + +# About + + + +multistream-select is protocol multiplexing per connection/stream. [Full spec here](https://github.com/multiformats/multistream-select) + +## Select a protocol flow + +The caller will send "interactive" messages, expecting for some acknowledgement from the callee, which will "select" the handler for the desired and supported protocol: + +``` +< /multistream-select/0.3.0 # i speak multistream-select/0.3.0 +> /multistream-select/0.3.0 # ok, let's speak multistream-select/0.3.0 +> /ipfs-dht/0.2.3 # i want to speak ipfs-dht/0.2.3 +< na # ipfs-dht/0.2.3 is not available +> /ipfs-dht/0.1.9 # What about ipfs-dht/0.1.9 ? +< /ipfs-dht/0.1.9 # ok let's speak ipfs-dht/0.1.9 -- in a sense acts as an ACK +> +> +> +``` + +# Install + +```console +$ npm i @libp2p/multistream-select +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/multistream-select/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/multistream-select/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/package.json new file mode 100644 index 000000000..993865e28 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/package.json @@ -0,0 +1,61 @@ +{ + "name": "@libp2p/multistream-select", + "version": "6.0.28", + "description": "JavaScript implementation of multistream-select", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/multistream-select#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "ipfs", + "libp2p", + "multistream", + "protocol", + "stream" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main" + }, + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/utils": "^6.7.1", + "it-length-prefixed": "^10.0.1", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/constants.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/constants.ts new file mode 100644 index 000000000..6f1b48364 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/constants.ts @@ -0,0 +1,5 @@ +export const PROTOCOL_ID = '/multistream/1.0.0' + +// Conforming to go-libp2p +// See https://github.com/multiformats/go-multistream/blob/master/multistream.go#L297 +export const MAX_PROTOCOL_LENGTH = 1024 diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/handle.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/handle.ts new file mode 100644 index 000000000..b82ee9c22 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/handle.ts @@ -0,0 +1,108 @@ +import { lpStream } from '@libp2p/utils' +import { encode } from 'it-length-prefixed' +import { Uint8ArrayList } from 'uint8arraylist' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { MAX_PROTOCOL_LENGTH, PROTOCOL_ID } from './constants.js' +import { readString } from './multistream.js' +import type { MultistreamSelectInit } from './index.js' +import type { MultiaddrConnection, MessageStream } from '@libp2p/interface' + +/** + * Handle multistream protocol selections for the given list of protocols. + * + * Note that after a protocol is handled `listener` can no longer be used. + * + * @param stream - A duplex iterable stream to listen on + * @param protocols - A list of protocols (or single protocol) that this listener is able to speak. + * @param options - an options object containing an AbortSignal and an optional boolean `writeBytes` - if this is true, `Uint8Array`s will be written into `duplex`, otherwise `Uint8ArrayList`s will + * @returns A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select` + * @example + * + * ```TypeScript + * import { pipe } from 'it-pipe' + * import * as mss from '@libp2p/multistream-select' + * import { Mplex } from '@libp2p/mplex' + * + * const muxer = new Mplex({ + * async onStream (muxedStream) { + * // mss.handle(handledProtocols) + * // Returns selected stream and protocol + * const { stream, protocol } = await mss.handle(muxedStream, [ + * '/ipfs-dht/1.0.0', + * '/ipfs-bitswap/1.0.0' + * ]) + * + * // Typically here we'd call the handler function that was registered in + * // libp2p for the given protocol: + * // e.g. handlers[protocol].handler(stream) + * // + * // If protocol was /ipfs-dht/1.0.0 it might do something like this: + * // try { + * // await pipe( + * // dhtStream, + * // source => (async function * () { + * // for await (const chunk of source) + * // // Incoming DHT data -> process and yield to respond + * // })(), + * // dhtStream + * // ) + * // } catch (err) { + * // // Error in stream + * // } + * } + * }) + * ``` + */ +export async function handle (stream: Stream, protocols: string | string[], options: MultistreamSelectInit = {}): Promise { + protocols = Array.isArray(protocols) ? protocols : [protocols] + + const log = stream.log.newScope('mss:handle') + log.trace('available protocols %s', protocols) + + const lp = lpStream(stream, { + ...options, + maxDataLength: MAX_PROTOCOL_LENGTH, + maxLengthLength: 2, // 2 bytes is enough to length-prefix MAX_PROTOCOL_LENGTH + stopPropagation: true + }) + + while (true) { + log.trace('reading incoming string') + const protocol = await readString(lp, options) + log.trace('read "%s"', protocol) + + if (protocol === PROTOCOL_ID) { + log.trace('respond with "%s" for "%s"', PROTOCOL_ID, protocol) + await lp.write(uint8ArrayFromString(`${PROTOCOL_ID}\n`), options) + log.trace('responded with "%s" for "%s"', PROTOCOL_ID, protocol) + continue + } + + if (protocols.includes(protocol)) { + log.trace('respond with "%s" for "%s"', protocol, protocol) + await lp.write(uint8ArrayFromString(`${protocol}\n`), options) + log.trace('responded with "%s" for "%s"', protocol, protocol) + + lp.unwrap() + + return protocol + } + + if (protocol === 'ls') { + // \n\n\n + const protos = new Uint8ArrayList( + ...protocols.map(p => encode.single(uint8ArrayFromString(`${p}\n`))), + uint8ArrayFromString('\n') + ) + + log.trace('respond with "%s" for %s', protocols, protocol) + await lp.write(protos, options) + log.trace('responded with "%s" for %s', protocols, protocol) + continue + } + + log.trace('respond with "na" for "%s"', protocol) + await lp.write(uint8ArrayFromString('na\n'), options) + log('responded with "na" for "%s"', protocol) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/index.ts new file mode 100644 index 000000000..2691b13ae --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/index.ts @@ -0,0 +1,42 @@ +/** + * @packageDocumentation + * + * multistream-select is protocol multiplexing per connection/stream. [Full spec here](https://github.com/multiformats/multistream-select) + * + * ## Select a protocol flow + * + * The caller will send "interactive" messages, expecting for some acknowledgement from the callee, which will "select" the handler for the desired and supported protocol: + * + * ``` + * < /multistream-select/0.3.0 # i speak multistream-select/0.3.0 + * > /multistream-select/0.3.0 # ok, let's speak multistream-select/0.3.0 + * > /ipfs-dht/0.2.3 # i want to speak ipfs-dht/0.2.3 + * < na # ipfs-dht/0.2.3 is not available + * > /ipfs-dht/0.1.9 # What about ipfs-dht/0.1.9 ? + * < /ipfs-dht/0.1.9 # ok let's speak ipfs-dht/0.1.9 -- in a sense acts as an ACK + * > + * > + * > + * ``` + */ + +import { PROTOCOL_ID } from './constants.js' +import type { AbortOptions } from '@libp2p/interface' +import type { LengthPrefixedStreamOpts } from '@libp2p/utils' +import type { Uint8ArrayList } from 'uint8arraylist' + +export { PROTOCOL_ID } + +export interface MultistreamSelectInit extends AbortOptions, Partial { + /** + * When false, and only a single protocol is being negotiated, use optimistic + * select to send both the protocol name and the first data buffer in the + * initial message, saving a round trip for connection establishment. + * + * @default true + */ + negotiateFully?: boolean +} + +export { select } from './select.js' +export { handle } from './handle.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/multistream.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/multistream.ts new file mode 100644 index 000000000..18729856e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/multistream.ts @@ -0,0 +1,21 @@ +import { InvalidMessageError } from '@libp2p/interface' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import type { AbortOptions } from '@libp2p/interface' +import type { LengthPrefixedStream } from '@libp2p/utils' + +const NewLine = uint8ArrayFromString('\n') + +/** + * Read a length-prefixed string from the passed stream, stripping the final newline character + */ +export async function readString (reader: LengthPrefixedStream, options?: AbortOptions): Promise { + const buf = await reader.read(options) + const arr = buf.subarray() + + if (arr.byteLength === 0 || arr[arr.length - 1] !== NewLine[0]) { + throw new InvalidMessageError('Missing newline') + } + + return uint8ArrayToString(arr).trimEnd() +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/select.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/select.ts new file mode 100644 index 000000000..c118d4cfa --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/src/select.ts @@ -0,0 +1,111 @@ +import { UnsupportedProtocolError } from '@libp2p/interface' +import { lpStream } from '@libp2p/utils' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { MAX_PROTOCOL_LENGTH } from './constants.js' +import { readString } from './multistream.js' +import { PROTOCOL_ID } from './index.js' +import type { MultistreamSelectInit } from './index.js' +import type { MessageStream } from '@libp2p/interface' + +/** + * Negotiate a protocol to use from a list of protocols. + * + * @param stream - A duplex iterable stream to dial on + * @param protocols - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made. + * @param options - An options object containing an AbortSignal and an optional boolean `writeBytes` - if this is true, `Uint8Array`s will be written into `duplex`, otherwise `Uint8ArrayList`s will + * @returns A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`. + * @example + * + * ```TypeScript + * import { pipe } from 'it-pipe' + * import * as mss from '@libp2p/multistream-select' + * import { Mplex } from '@libp2p/mplex' + * + * const muxer = new Mplex() + * const muxedStream = muxer.newStream() + * + * // mss.select(protocol(s)) + * // Select from one of the passed protocols (in priority order) + * // Returns selected stream and protocol + * const { stream: dhtStream, protocol } = await mss.select(muxedStream, [ + * // This might just be different versions of DHT, but could be different implementations + * '/ipfs-dht/2.0.0', // Most of the time this will probably just be one item. + * '/ipfs-dht/1.0.0' + * ]) + * + * // Typically this stream will be passed back to the caller of libp2p.dialProtocol + * // + * // ...it might then do something like this: + * // try { + * // await pipe( + * // [uint8ArrayFromString('Some DHT data')] + * // dhtStream, + * // async source => { + * // for await (const chunk of source) + * // // DHT response data + * // } + * // ) + * // } catch (err) { + * // // Error in stream + * // } + * ``` + */ +export async function select (stream: Stream, protocols: string | string[], options: MultistreamSelectInit = {}): Promise { + protocols = Array.isArray(protocols) ? [...protocols] : [protocols] + + const log = stream.log.newScope('mss:select') + + const lp = lpStream(stream, { + ...options, + maxDataLength: MAX_PROTOCOL_LENGTH, + stopPropagation: true + }) + const protocol = protocols.shift() + + if (protocol == null) { + throw new Error('At least one protocol must be specified') + } + + log.trace('write ["%s", "%s"]', PROTOCOL_ID, protocol) + const p1 = uint8ArrayFromString(`${PROTOCOL_ID}\n`) + const p2 = uint8ArrayFromString(`${protocol}\n`) + await lp.writeV([p1, p2], options) + + log.trace('reading multistream-select header') + let response = await readString(lp, options) + log.trace('read "%s"', response) + + // Read the protocol response if we got the protocolId in return + if (response === PROTOCOL_ID) { + log.trace('reading protocol response') + response = await readString(lp, options) + log.trace('read "%s"', response) + } + + // We're done + if (response === protocol) { + log.trace('selected "%s" as first offer', response) + lp.unwrap() + + return protocol + } + + // We haven't gotten a valid ack, try the other protocols + for (const protocol of protocols) { + log.trace('write "%s"', protocol) + await lp.write(uint8ArrayFromString(`${protocol}\n`), options) + + log.trace('reading protocol response') + const response = await readString(lp, options) + log.trace('read "%s" for "%s"', response, protocol) + + if (response === protocol) { + log.trace('selected "%s" after negotiation', response) + lp.unwrap() + + return protocol + } + } + + throw new UnsupportedProtocolError('protocol selection failed') +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/multistream-select/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/README.md new file mode 100644 index 000000000..0c1ee8007 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/README.md @@ -0,0 +1,159 @@ +# @libp2p/peer-collections + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> Stores values against a peer id + +# About + + + +We can't use PeerIds as collection keys because collection keys are compared using same-value-zero equality, so this is just a group of collections that stringifies PeerIds before storing them. + +PeerIds cache stringified versions of themselves so this should be a cheap operation. + +Tracked versions are also available which report their current size to the libp2p Metrics collector. + +## Example - Peer lists + +```TypeScript +import { peerList } from '@libp2p/peer-collections' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const list = peerList() +list.push(peerId) +``` + +## Example - Tracked peer lists + +```TypeScript +import { trackedPeerList } from '@libp2p/peer-collections' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { createLibp2p } from 'libp2p' + +const libp2p = await createLibp2p() +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const list = trackedPeerList({ name: 'my_metric_name', metrics: libp2p.metrics }) +list.push(peerId) +``` + +## Example - Peer maps + +```TypeScript +import { peerMap } from '@libp2p/peer-collections' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const map = peerMap() +map.set(peerId, 'value') +``` + +## Example - Tracked peer maps + +```TypeScript +import { trackedPeerMap } from '@libp2p/peer-collections' +import { createLibp2p } from 'libp2p' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + +const libp2p = await createLibp2p() +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const map = trackedPeerMap({ name: 'my_metric_name', metrics: libp2p.metrics }) +map.set(peerId, 'value') +``` + +## Example - Peer sets + +```TypeScript +import { peerSet } from '@libp2p/peer-collections' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const set = peerSet() +set.add(peerId) +``` + +## Example - Tracked peer sets + +```TypeScript +import { trackedPeerSet } from '@libp2p/peer-collections' +import { createLibp2p } from 'libp2p' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + +const libp2p = await createLibp2p() +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const set = trackedPeerSet({ name: 'my_metric_name', metrics: libp2p.metrics }) +set.add(peerId) +``` + +## Example - Peer filters + +```TypeScript +import { peerFilter } from '@libp2p/peer-collections' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const filter = peerFilter(1024) +filter.has(peerId) // false +filter.add(peerId) +filter.has(peerId) // true +``` + +# Install + +```console +$ npm i @libp2p/peer-collections +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/peer-collections/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/peer-collections/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/package.json new file mode 100644 index 000000000..ae53acfee --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/package.json @@ -0,0 +1,56 @@ +{ + "name": "@libp2p/peer-collections", + "version": "6.0.34", + "description": "Stores values against a peer id", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/peer-collections#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "IPFS" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main" + }, + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/peer-id": "^5.1.8", + "@libp2p/utils": "^6.7.1", + "multiformats": "^13.3.6" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/filter.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/filter.ts new file mode 100644 index 000000000..0a37c5b99 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/filter.ts @@ -0,0 +1,54 @@ +import { createScalableCuckooFilter } from '@libp2p/utils' +import type { PeerId } from '@libp2p/interface' +import type { Filter } from '@libp2p/utils' + +/** + * Uses a Cuckoo filter to implement a mechanism for deduplicating PeerIds in a + * way that uses a smaller amount of memory than a PeerSet. + */ +export class PeerFilter { + private readonly filter: Filter + + constructor (size: number, errorRate?: number) { + this.filter = createScalableCuckooFilter(size, errorRate) + } + + has (peerId: PeerId): boolean { + return this.filter.has(peerId.toMultihash().bytes) + } + + add (peerId: PeerId): void { + this.filter.add(peerId.toMultihash().bytes) + } + + remove (peerId: PeerId): void { + this.filter.remove?.(peerId.toMultihash().bytes) + } +} + +/** + * Create and return a PeerFilter. This can be used by topologies to prevent + * them receiving duplicate notifications for a peer that connects repeatedly. + * + * @example + * + * ```TypeScript + * import { peerFilter } from '@libp2p/peer-collections' + * import type { Registrar } from '@libp2p/interface-internal' + * + * const registrar: Registrar + * + * registrar.register('/my/protocol/1.0.0', { + * filter: peerFilter(), + * onConnect: (peerId) => { + * // will only be invoked for a given peerId once + * } + * }) + * ``` + * + * @param size - The maximum number of peers expected to be added to the filter + * @param errorRate - The acceptable error rate + */ +export function peerFilter (size: number, errorRate: number = 0.001): PeerFilter { + return new PeerFilter(size, errorRate) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/index.ts new file mode 100644 index 000000000..c5bdbf4ae --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/index.ts @@ -0,0 +1,120 @@ +/** + * @packageDocumentation + * + * We can't use PeerIds as collection keys because collection keys are compared using same-value-zero equality, so this is just a group of collections that stringifies PeerIds before storing them. + * + * PeerIds cache stringified versions of themselves so this should be a cheap operation. + * + * Tracked versions are also available which report their current size to the libp2p Metrics collector. + * + * @example Peer lists + * + * ```TypeScript + * import { peerList } from '@libp2p/peer-collections' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const list = peerList() + * list.push(peerId) + * ``` + * + * @example Tracked peer lists + * + * ```TypeScript + * import { trackedPeerList } from '@libp2p/peer-collections' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * import { createLibp2p } from 'libp2p' + * + * const libp2p = await createLibp2p() + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const list = trackedPeerList({ name: 'my_metric_name', metrics: libp2p.metrics }) + * list.push(peerId) + * ``` + * + * @example Peer maps + * + * ```TypeScript + * import { peerMap } from '@libp2p/peer-collections' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const map = peerMap() + * map.set(peerId, 'value') + * ``` + * + * @example Tracked peer maps + * + * ```TypeScript + * import { trackedPeerMap } from '@libp2p/peer-collections' + * import { createLibp2p } from 'libp2p' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const libp2p = await createLibp2p() + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const map = trackedPeerMap({ name: 'my_metric_name', metrics: libp2p.metrics }) + * map.set(peerId, 'value') + * ``` + * + * @example Peer sets + * + * ```TypeScript + * import { peerSet } from '@libp2p/peer-collections' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const set = peerSet() + * set.add(peerId) + * ``` + * + * @example Tracked peer sets + * + * ```TypeScript + * import { trackedPeerSet } from '@libp2p/peer-collections' + * import { createLibp2p } from 'libp2p' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const libp2p = await createLibp2p() + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const set = trackedPeerSet({ name: 'my_metric_name', metrics: libp2p.metrics }) + * set.add(peerId) + * ``` + * + * @example Peer filters + * + * ```TypeScript + * import { peerFilter } from '@libp2p/peer-collections' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const filter = peerFilter(1024) + * filter.has(peerId) // false + * filter.add(peerId) + * filter.has(peerId) // true + * ``` + */ + +export { PeerMap, peerMap } from './map.js' +export { PeerSet, peerSet } from './set.js' +export { PeerList, peerList } from './list.js' +export { PeerFilter, peerFilter } from './filter.js' + +export { trackedPeerMap } from './tracked-map.js' +export type { TrackedPeerMapInit } from './tracked-map.js' +export { trackedPeerSet } from './tracked-set.js' +export type { TrackedPeerSetInit } from './tracked-set.js' +export { trackedPeerList } from './tracked-list.js' +export type { TrackedPeerListInit } from './tracked-list.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/list.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/list.ts new file mode 100644 index 000000000..8cf001748 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/list.ts @@ -0,0 +1,159 @@ +import { mapIterable } from './util.js' +import type { PeerId } from '@libp2p/interface' + +/** + * We can't use PeerIds as list entries because list entries are + * compared using same-value-zero equality, so this is just + * a map that stringifies the PeerIds before storing them. + * + * PeerIds cache stringified versions of themselves so this + * should be a cheap operation. + * + * @example + * + * ```TypeScript + * import { peerList } from '@libp2p/peer-collections' + * + * const list = peerList() + * list.push(peerId) + * ``` + */ +export class PeerList { + private list: PeerId[] + + constructor (list?: PeerList | Iterable) { + this.list = [] + + if (list != null) { + for (const value of list) { + this.list.push(value) + } + } + } + + [Symbol.iterator] (): IterableIterator { + return mapIterable<[number, PeerId], PeerId>( + this.list.entries(), + (val) => { + return val[1] + } + ) + } + + concat (list: PeerList): PeerList { + const output = new PeerList(this) + + for (const value of list) { + output.push(value) + } + + return output + } + + entries (): IterableIterator<[number, PeerId]> { + return mapIterable<[number, PeerId], [number, PeerId]>( + this.list.entries(), + (val) => { + return [val[0], val[1]] + } + ) + } + + every (predicate: (peerId: PeerId, index: number, arr: PeerList) => boolean): boolean { + return this.list.every((peerId, index) => { + return predicate(peerId, index, this) + }) + } + + filter (predicate: (peerId: PeerId, index: number, arr: PeerList) => boolean): PeerList { + const output = new PeerList() + + this.list.forEach((peerId, index) => { + if (predicate(peerId, index, this)) { + output.push(peerId) + } + }) + + return output + } + + find (predicate: (peerId: PeerId, index: number, arr: PeerList) => boolean): PeerId | undefined { + const peerId = this.list.find((peerId, index) => { + return predicate(peerId, index, this) + }) + + if (peerId == null) { + return undefined + } + + return peerId + } + + findIndex (predicate: (peerId: PeerId, index: number, arr: PeerList) => boolean): number { + return this.list.findIndex((peerId, index) => { + return predicate(peerId, index, this) + }) + } + + forEach (predicate: (peerId: PeerId, index: number, arr: PeerList) => void): void { + this.list.forEach((peerId, index) => { + predicate(peerId, index, this) + }) + } + + includes (peerId: PeerId): boolean { + return this.includes(peerId) + } + + indexOf (peerId: PeerId): number { + return this.list.findIndex(id => id.equals(peerId)) + } + + pop (): PeerId | undefined { + const peerId = this.list.pop() + + if (peerId == null) { + return undefined + } + + return peerId + } + + push (...peerIds: PeerId[]): void { + for (const peerId of peerIds) { + this.list.push(peerId) + } + } + + shift (): PeerId | undefined { + const peerId = this.list.shift() + + if (peerId == null) { + return undefined + } + + return peerId + } + + unshift (...peerIds: PeerId[]): number { + let len = this.list.length + + for (let i = peerIds.length - 1; i > -1; i--) { + len = this.list.unshift(peerIds[i]) + } + + return len + } + + clear (): void { + this.list = [] + } + + get length (): number { + return this.list.length + } +} + +export function peerList (): PeerList { + return new PeerList() +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/map.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/map.ts new file mode 100644 index 000000000..e40b63da1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/map.ts @@ -0,0 +1,93 @@ +import { mapIterable } from './util.js' +import type { PeerId } from '@libp2p/interface' + +/** + * We can't use PeerIds as map keys because map keys are + * compared using same-value-zero equality, so this is just + * a map that stringifies the PeerIds before storing them. + * + * PeerIds cache stringified versions of themselves so this + * should be a cheap operation. + * + * @example + * + * ```TypeScript + * import { peerMap } from '@libp2p/peer-collections' + * + * const map = peerMap() + * map.set(peerId, 'value') + * ``` + */ +export class PeerMap { + private readonly map: Map + + constructor (map?: PeerMap) { + this.map = new Map() + + if (map != null) { + for (const [key, value] of map.entries()) { + this.map.set(key.toString(), { key, value }) + } + } + } + + [Symbol.iterator] (): IterableIterator<[PeerId, T]> { + return this.entries() + } + + clear (): void { + this.map.clear() + } + + delete (peer: PeerId): boolean { + return this.map.delete(peer.toString()) + } + + entries (): IterableIterator<[PeerId, T]> { + return mapIterable<[string, { key: PeerId, value: T }], [PeerId, T]>( + this.map.entries(), + (val) => { + return [val[1].key, val[1].value] + } + ) + } + + forEach (fn: (value: T, key: PeerId, map: PeerMap) => void): void { + this.map.forEach((value, key) => { + fn(value.value, value.key, this) + }) + } + + get (peer: PeerId): T | undefined { + return this.map.get(peer.toString())?.value + } + + has (peer: PeerId): boolean { + return this.map.has(peer.toString()) + } + + set (peer: PeerId, value: T): void { + this.map.set(peer.toString(), { key: peer, value }) + } + + keys (): IterableIterator { + return mapIterable<{ key: PeerId, value: T }, PeerId>( + this.map.values(), + (val) => { + return val.key + } + ) + } + + values (): IterableIterator { + return mapIterable(this.map.values(), (val) => val.value) + } + + get size (): number { + return this.map.size + } +} + +export function peerMap (): PeerMap { + return new PeerMap() +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/set.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/set.ts new file mode 100644 index 000000000..4e89a8e41 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/set.ts @@ -0,0 +1,127 @@ +import { mapIterable, peerIdFromString } from './util.js' +import type { PeerId } from '@libp2p/interface' + +/** + * We can't use PeerIds as set entries because set entries are + * compared using same-value-zero equality, so this is just + * a map that stringifies the PeerIds before storing them. + * + * PeerIds cache stringified versions of themselves so this + * should be a cheap operation. + * + * @example + * + * ```TypeScript + * import { peerSet } from '@libp2p/peer-collections' + * + * const set = peerSet() + * set.add(peerId) + * ``` + */ +export class PeerSet { + private readonly set: Set + + constructor (set?: PeerSet | Iterable) { + this.set = new Set() + + if (set != null) { + for (const key of set) { + this.set.add(key.toString()) + } + } + } + + get size (): number { + return this.set.size + } + + [Symbol.iterator] (): IterableIterator { + return this.values() + } + + add (peer: PeerId): void { + this.set.add(peer.toString()) + } + + clear (): void { + this.set.clear() + } + + delete (peer: PeerId): void { + this.set.delete(peer.toString()) + } + + entries (): IterableIterator<[PeerId, PeerId]> { + return mapIterable<[string, string], [PeerId, PeerId]>( + this.set.entries(), + (val) => { + const peerId = peerIdFromString(val[0]) + + return [peerId, peerId] + } + ) + } + + forEach (predicate: (peerId: PeerId, index: PeerId, set: PeerSet) => void): void { + this.set.forEach((str) => { + const peerId = peerIdFromString(str) + + predicate(peerId, peerId, this) + }) + } + + has (peer: PeerId): boolean { + return this.set.has(peer.toString()) + } + + values (): IterableIterator { + return mapIterable( + this.set.values(), + (val) => { + return peerIdFromString(val) + } + ) + } + + intersection (other: PeerSet): PeerSet { + const output = new PeerSet() + + for (const peerId of other) { + if (this.has(peerId)) { + output.add(peerId) + } + } + + return output + } + + difference (other: PeerSet): PeerSet { + const output = new PeerSet() + + for (const peerId of this) { + if (!other.has(peerId)) { + output.add(peerId) + } + } + + return output + } + + union (other: PeerSet): PeerSet { + const output = new PeerSet() + + for (const peerId of other) { + output.add(peerId) + } + + for (const peerId of this) { + output.add(peerId) + } + + return output + } +} + +export function peerSet (): PeerSet { + return new PeerSet() +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-list.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-list.ts new file mode 100644 index 000000000..0519cf8de --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-list.ts @@ -0,0 +1,80 @@ +import { PeerList } from './list.js' +import type { Metric, Metrics, PeerId } from '@libp2p/interface' + +export interface TrackedPeerListInit { + name: string + metrics?: Metrics +} + +class TrackedPeerList extends PeerList { + private readonly metric: Metric + + constructor (init: Required) { + super() + + const { name, metrics } = init + + this.metric = metrics.registerMetric(name) + this.updateComponentMetric() + } + + pop (): PeerId | undefined { + const peerId = super.pop() + this.updateComponentMetric() + return peerId + } + + push (...peerIds: PeerId[]): void { + super.push(...peerIds) + this.updateComponentMetric() + } + + shift (): PeerId | undefined { + const peerId = super.shift() + this.updateComponentMetric() + return peerId + } + + unshift (...peerIds: PeerId[]): number { + const result = super.unshift(...peerIds) + this.updateComponentMetric() + return result + } + + clear (): void { + super.clear() + this.updateComponentMetric() + } + + private updateComponentMetric (): void { + this.metric.update(this.length) + } +} + +/** + * Creates a PeerList that reports it's size to the libp2p Metrics service + * + * @example + * + * ```Typescript + * import { trackedPeerList } from '@libp2p/peer-collections' + * import { createLibp2p } from 'libp2p' + * + * const libp2p = await createLibp2p() + * + * const list = trackedPeerList({ name: 'my_metric_name', metrics: libp2p.metrics }) + * list.push(peerId) + * ``` + */ +export function trackedPeerList (config: TrackedPeerListInit): PeerList { + const { name, metrics } = config + let map: PeerList + + if (metrics != null) { + map = new TrackedPeerList({ name, metrics }) + } else { + map = new PeerList() + } + + return map +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-map.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-map.ts new file mode 100644 index 000000000..78efc66e3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-map.ts @@ -0,0 +1,69 @@ +import { PeerMap } from './map.js' +import type { Metric, Metrics, PeerId } from '@libp2p/interface' + +export interface TrackedPeerMapInit { + name: string + metrics?: Metrics +} + +class TrackedPeerMap extends PeerMap { + private readonly metric: Metric + + constructor (init: Required) { + super() + + const { name, metrics } = init + + this.metric = metrics.registerMetric(name) + this.updateComponentMetric() + } + + set (key: PeerId, value: V): this { + super.set(key, value) + this.updateComponentMetric() + return this + } + + delete (key: PeerId): boolean { + const deleted = super.delete(key) + this.updateComponentMetric() + return deleted + } + + clear (): void { + super.clear() + this.updateComponentMetric() + } + + private updateComponentMetric (): void { + this.metric.update(this.size) + } +} + +/** + * Creates a PeerMap that reports it's size to the libp2p Metrics service + * + * @example + * + * ```Typescript + * import { trackedPeerMap } from '@libp2p/peer-collections' + * import { createLibp2p } from 'libp2p' + * + * const libp2p = await createLibp2p() + * + * const list = trackedPeerMap({ name: 'my_metric_name', metrics: libp2p.metrics }) + * map.set(peerId, 'value') + * ``` + */ +export function trackedPeerMap (config: TrackedPeerMapInit): PeerMap { + const { name, metrics } = config + let map: PeerMap + + if (metrics != null) { + map = new TrackedPeerMap({ name, metrics }) + } else { + map = new PeerMap() + } + + return map +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-set.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-set.ts new file mode 100644 index 000000000..2a80d9a78 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/tracked-set.ts @@ -0,0 +1,67 @@ +import { PeerSet } from './set.js' +import type { Metric, Metrics, PeerId } from '@libp2p/interface' + +export interface TrackedPeerSetInit { + name: string + metrics?: Metrics +} + +class TrackedPeerSet extends PeerSet { + private readonly metric: Metric + + constructor (init: Required) { + super() + + const { name, metrics } = init + + this.metric = metrics.registerMetric(name) + this.updateComponentMetric() + } + + add (peer: PeerId): void { + super.add(peer) + this.updateComponentMetric() + } + + delete (peer: PeerId): void { + super.delete(peer) + this.updateComponentMetric() + } + + clear (): void { + super.clear() + this.updateComponentMetric() + } + + private updateComponentMetric (): void { + this.metric.update(this.size) + } +} + +/** + * Creates a PeerSet that reports it's size to the libp2p Metrics service + * + * @example Tracked peer sets + * + * ```Typescript + * import { trackedPeerSet } from '@libp2p/peer-collections' + * import { createLibp2p } from 'libp2p' + * + * const libp2p = await createLibp2p() + * + * const list = trackedPeerSet({ name: 'my_metric_name', metrics: libp2p.metrics }) + * map.add(peerId) + * ``` + */ +export function trackedPeerSet (config: TrackedPeerSetInit): PeerSet { + const { name, metrics } = config + let map: PeerSet + + if (metrics != null) { + map = new TrackedPeerSet({ name, metrics }) + } else { + map = new PeerSet() + } + + return map +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/util.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/util.ts new file mode 100644 index 000000000..d85ed8934 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/src/util.ts @@ -0,0 +1,40 @@ +import { peerIdFromMultihash } from '@libp2p/peer-id' +import { base58btc } from 'multiformats/bases/base58' +import * as Digest from 'multiformats/hashes/digest' +import type { PeerId } from '@libp2p/interface' + +/** + * Calls the passed map function on every entry of the passed iterable iterator + */ +export function mapIterable (iter: IterableIterator, map: (val: T) => R): IterableIterator { + const iterator: IterableIterator = { + [Symbol.iterator]: () => { + return iterator + }, + next: () => { + const next = iter.next() + const val = next.value + + if (next.done === true || val == null) { + const result: IteratorReturnResult = { + done: true, + value: undefined + } + + return result + } + + return { + done: false, + value: map(val) + } + } + } + + return iterator +} + +export function peerIdFromString (str: string): PeerId { + const multihash = Digest.decode(base58btc.decode(`z${str}`)) + return peerIdFromMultihash(multihash) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-collections/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/README.md new file mode 100644 index 000000000..95d98a74b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/README.md @@ -0,0 +1,179 @@ +# @libp2p/peer-record + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> Used to transfer signed peer data across the network + +# About + + + +Libp2p nodes need to store data in a public location (e.g. a DHT), or rely on potentially untrustworthy intermediaries to relay information over its lifetime. Accordingly, libp2p nodes need to be able to verify that the data came from a specific peer and that it hasn't been tampered with. + +## Envelope + +Libp2p provides an all-purpose data container called **envelope**. It was created to enable the distribution of verifiable records, which we can prove originated from the addressed peer itself. The envelope includes a signature of the data, so that its authenticity is verified. + +This envelope stores a marshaled record implementing the [interface-record](https://github.com/libp2p/js-libp2p/blob/main/packages/interface/src/record/index.ts). These Records are designed to be serialized to bytes and placed inside of the envelopes before being shared with other peers. + +You can read further about the envelope in [RFC 0002 - Signed Envelopes](https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md). For the original discussion about it you can look at the PR that was used to create it: [libp2p/specs#217](https://github.com/libp2p/specs/pull/217). + +## Example - Creating a peer record + +Create an envelope with an instance of an [interface-record](https://github.com/libp2p/js-libp2p/blob/main/packages/interface/src/record/index.ts) implementation and prepare it for being exchanged: + +```TypeScript +import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' + +const privateKey = await generateKeyPair('Ed25519') +const peerId = peerIdFromPrivateKey(privateKey) + +const record = new PeerRecord({ + peerId, + // ...other data +}) + +const envelope = await RecordEnvelope.seal(record, privateKey) +const wireData = envelope.marshal() +``` + +## Example - Consuming a peer record + +Consume a received envelope `wireData` and transform it back to a record: + +```TypeScript +import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record' + +const wireData = Uint8Array.from([0, 1, 2, 3, 4]) +const envelope = await RecordEnvelope.openAndCertify(wireData, PeerRecord.DOMAIN) + +const record = PeerRecord.createFromProtobuf(envelope.payload) +``` + +## Peer Record + +All libp2p nodes keep a `PeerStore`, that among other information stores a set of known addresses for each peer, which can come from a variety of sources. + +Libp2p peer records were created to enable the distribution of verifiable address records, which we can prove originated from the addressed peer itself. With such guarantees, libp2p is able to prioritize addresses based on their authenticity, with the most strict strategy being to only dial certified addresses (no strategies have been implemented at the time of writing). + +A peer record contains the peers' publicly reachable listen addresses, and may be extended in the future to contain additional metadata relevant to routing. It also contains a `seqNumber` field, a timestamp per the spec, so that we can verify the most recent record. + +You can read further about the Peer Record in [RFC 0003 - Peer Routing Records](https://github.com/libp2p/specs/blob/master/RFC/0003-routing-records.md). For the original discussion about it you can view the PR that created the RFC: [libp2p/specs#217](https://github.com/libp2p/specs/pull/217). + +## Example + +Create a new Peer Record + +```TypeScript +import { PeerRecord } from '@libp2p/peer-record' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { multiaddr } from '@multiformats/multiaddr' + +const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + +const record = new PeerRecord({ + peerId: peerId, + multiaddrs: [ + multiaddr('/ip4/...'), + multiaddr('/ip4/...') + ] +}) +``` + +## Example + +Create a Peer Record from a protobuf + +```TypeScript +import { PeerRecord } from '@libp2p/peer-record' + +const data = Uint8Array.from([0, 1, 2, 3, 4]) +const record = PeerRecord.createFromProtobuf(data) +``` + +## Libp2p Flows + +### Self Record + +Once a libp2p node has started and is listening on a set of multiaddrs, its own peer record can be created. + +The identify service is responsible for creating the self record when the identify protocol kicks in for the first time. This record will be stored for future needs of the identify protocol when connecting with other peers. + +### Self record Updates + +While creating peer records is fairly trivial, addresses are not static and might be modified at arbitrary times. This can happen via an Address Manager API, or even through AutoRelay/AutoNAT. + +When a libp2p node changes its listen addresses, the identify service will be informed. Once that happens, the identify service creates a new self record and stores it. With the new record, the identify push/delta protocol will be used to communicate this change to the connected peers. + +### Subsystem receiving a record + +Considering that a node can discover other peers' addresses from a variety of sources, Libp2p PeerStore can differentiate the addresses that were obtained through a signed peer record. + +Once a record is received and its signature properly validated, its envelope is stored in the AddressBook in its byte representation. The `seqNumber` remains unmarshaled so that we can quickly compare it against incoming records to determine the most recent record. + +The AddressBook Addresses will be updated with the content of the envelope with a certified property. This allows other subsystems to identify the known certified addresses of a peer. + +### Subsystem providing a record + +Libp2p subsystems that exchange other peers information will provide the envelope that they received by those peers. As a result, other peers can verify if the envelope was really created by the addressed peer. + +When a subsystem wants to provide a record, it will get it from the AddressBook, if it exists. Other subsystems are also able to provide the self record, since it is also stored in the AddressBook. + +## Future Work + +- Persistence only considering certified addresses? +- Peers may not know their own addresses. It's often impossible to automatically infer one's own public address, and peers may need to rely on third party peers to inform them of their observed public addresses. +- A peer may inadvertently or maliciously sign an address that they do not control. In other words, a signature isn't a guarantee that a given address is valid. +- Some addresses may be ambiguous. For example, addresses on a private subnet are valid within that subnet but are useless on the public internet. +- Once all these pieces are in place, we will also need a way to prioritize addresses based on their authenticity, that is, the dialer can prioritize self-certified addresses over addresses from an unknown origin. +- Modular dialer? (taken from go PR notes) + - With the modular dialer, users should easily be able to configure precedence. With dialer v1, anything we do to prioritize dials is gonna be spaghetti and adhoc. With the modular dialer, you’d be able to specify the order of dials when instantiating the pipeline. + - Multiple parallel dials. We already have the issue where new addresses aren't added to existing dials. + +# Install + +```console +$ npm i @libp2p/peer-record +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/peer-record/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/peer-record/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/package.json new file mode 100644 index 000000000..4a3ff6eae --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/package.json @@ -0,0 +1,62 @@ +{ + "name": "@libp2p/peer-record", + "version": "8.0.34", + "description": "Used to transfer signed peer data across the network", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/peer-record#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "IPFS" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "generate": "protons src/envelope/envelope.proto src/peer-record/peer-record.proto", + "build": "aegir build", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main" + }, + "dependencies": { + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "@libp2p/peer-id": "^5.1.8", + "@multiformats/multiaddr": "^12.4.4", + "multiformats": "^13.3.6", + "protons-runtime": "^5.5.0", + "uint8-varint": "^2.0.4", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/envelope.proto b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/envelope.proto new file mode 100644 index 000000000..5b80cf504 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/envelope.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +message Envelope { + // public_key is the public key of the keypair the enclosed payload was + // signed with. + bytes public_key = 1; + + // payload_type encodes the type of payload, so that it can be deserialized + // deterministically. + bytes payload_type = 2; + + // payload is the actual payload carried inside this envelope. + bytes payload = 3; + + // signature is the signature produced by the private key corresponding to + // the enclosed public key, over the payload, prefixing a domain string for + // additional security. + bytes signature = 5; +} \ No newline at end of file diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/envelope.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/envelope.ts new file mode 100644 index 000000000..100a945d9 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/envelope.ts @@ -0,0 +1,97 @@ +import { decodeMessage, encodeMessage, message } from 'protons-runtime' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' +import type { Codec, DecodeOptions } from 'protons-runtime' +import type { Uint8ArrayList } from 'uint8arraylist' + +export interface Envelope { + publicKey: Uint8Array + payloadType: Uint8Array + payload: Uint8Array + signature: Uint8Array +} + +export namespace Envelope { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.publicKey != null && obj.publicKey.byteLength > 0)) { + w.uint32(10) + w.bytes(obj.publicKey) + } + + if ((obj.payloadType != null && obj.payloadType.byteLength > 0)) { + w.uint32(18) + w.bytes(obj.payloadType) + } + + if ((obj.payload != null && obj.payload.byteLength > 0)) { + w.uint32(26) + w.bytes(obj.payload) + } + + if ((obj.signature != null && obj.signature.byteLength > 0)) { + w.uint32(42) + w.bytes(obj.signature) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + publicKey: uint8ArrayAlloc(0), + payloadType: uint8ArrayAlloc(0), + payload: uint8ArrayAlloc(0), + signature: uint8ArrayAlloc(0) + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.publicKey = reader.bytes() + break + } + case 2: { + obj.payloadType = reader.bytes() + break + } + case 3: { + obj.payload = reader.bytes() + break + } + case 5: { + obj.signature = reader.bytes() + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }) + } + + return _codec + } + + export const encode = (obj: Partial): Uint8Array => { + return encodeMessage(obj, Envelope.codec()) + } + + export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): Envelope => { + return decodeMessage(buf, Envelope.codec(), opts) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/errors.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/errors.ts new file mode 100644 index 000000000..8442e107f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/errors.ts @@ -0,0 +1,9 @@ +/** + * The key in the record is not valid for the domain + */ +export class InvalidSignatureError extends Error { + constructor (message = 'Invalid signature') { + super(message) + this.name = 'InvalidSignatureError' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/index.ts new file mode 100644 index 000000000..9434477c2 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/envelope/index.ts @@ -0,0 +1,153 @@ +import { publicKeyFromProtobuf, publicKeyToProtobuf } from '@libp2p/crypto/keys' +import * as varint from 'uint8-varint' +import { Uint8ArrayList } from 'uint8arraylist' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { fromString as uint8arraysFromString } from 'uint8arrays/from-string' +import { Envelope as Protobuf } from './envelope.js' +import { InvalidSignatureError } from './errors.js' +import type { Record, Envelope, PrivateKey, PublicKey } from '@libp2p/interface' +import type { AbortOptions } from '@multiformats/multiaddr' + +export interface RecordEnvelopeInit { + publicKey: PublicKey + payloadType: Uint8Array + payload: Uint8Array + signature: Uint8Array +} + +export class RecordEnvelope implements Envelope { + /** + * Unmarshal a serialized Envelope protobuf message + */ + static createFromProtobuf = (data: Uint8Array | Uint8ArrayList): RecordEnvelope => { + const envelopeData = Protobuf.decode(data) + const publicKey = publicKeyFromProtobuf(envelopeData.publicKey) + + return new RecordEnvelope({ + publicKey, + payloadType: envelopeData.payloadType, + payload: envelopeData.payload, + signature: envelopeData.signature + }) + } + + /** + * Seal marshals the given Record, places the marshaled bytes inside an Envelope + * and signs it with the given peerId's private key + */ + static seal = async (record: Record, privateKey: PrivateKey, options?: AbortOptions): Promise => { + if (privateKey == null) { + throw new Error('Missing private key') + } + + const domain = record.domain + const payloadType = record.codec + const payload = record.marshal() + const signData = formatSignaturePayload(domain, payloadType, payload) + const signature = await privateKey.sign(signData.subarray(), options) + + return new RecordEnvelope({ + publicKey: privateKey.publicKey, + payloadType, + payload, + signature + }) + } + + /** + * Open and certify a given marshaled envelope. + * Data is unmarshaled and the signature validated for the given domain. + */ + static openAndCertify = async (data: Uint8Array | Uint8ArrayList, domain: string, options?: AbortOptions): Promise => { + const envelope = RecordEnvelope.createFromProtobuf(data) + const valid = await envelope.validate(domain, options) + + if (!valid) { + throw new InvalidSignatureError('Envelope signature is not valid for the given domain') + } + + return envelope + } + + public publicKey: PublicKey + public payloadType: Uint8Array + public payload: Uint8Array + public signature: Uint8Array + public marshaled?: Uint8Array + + /** + * The Envelope is responsible for keeping an arbitrary signed record + * by a libp2p peer. + */ + constructor (init: RecordEnvelopeInit) { + const { publicKey, payloadType, payload, signature } = init + + this.publicKey = publicKey + this.payloadType = payloadType + this.payload = payload + this.signature = signature + } + + /** + * Marshal the envelope content + */ + marshal (): Uint8Array { + if (this.marshaled == null) { + this.marshaled = Protobuf.encode({ + publicKey: publicKeyToProtobuf(this.publicKey), + payloadType: this.payloadType, + payload: this.payload.subarray(), + signature: this.signature + }) + } + + return this.marshaled + } + + /** + * Verifies if the other Envelope is identical to this one + */ + equals (other?: Envelope): boolean { + if (other == null) { + return false + } + + return uint8ArrayEquals(this.marshal(), other.marshal()) + } + + /** + * Validate envelope data signature for the given domain + */ + async validate (domain: string, options?: AbortOptions): Promise { + const signData = formatSignaturePayload(domain, this.payloadType, this.payload) + + return this.publicKey.verify(signData.subarray(), this.signature, options) + } +} + +/** + * Helper function that prepares a Uint8Array to sign or verify a signature + */ +const formatSignaturePayload = (domain: string, payloadType: Uint8Array, payload: Uint8Array | Uint8ArrayList): Uint8ArrayList => { + // When signing, a peer will prepare a Uint8Array by concatenating the following: + // - The length of the domain separation string string in bytes + // - The domain separation string, encoded as UTF-8 + // - The length of the payload_type field in bytes + // - The value of the payload_type field + // - The length of the payload field in bytes + // - The value of the payload field + + const domainUint8Array = uint8arraysFromString(domain) + const domainLength = varint.encode(domainUint8Array.byteLength) + const payloadTypeLength = varint.encode(payloadType.length) + const payloadLength = varint.encode(payload.length) + + return new Uint8ArrayList( + domainLength, + domainUint8Array, + payloadTypeLength, + payloadType, + payloadLength, + payload + ) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/index.ts new file mode 100644 index 000000000..9467dfe3a --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/index.ts @@ -0,0 +1,133 @@ +/** + * @packageDocumentation + * + * Libp2p nodes need to store data in a public location (e.g. a DHT), or rely on potentially untrustworthy intermediaries to relay information over its lifetime. Accordingly, libp2p nodes need to be able to verify that the data came from a specific peer and that it hasn't been tampered with. + * + * ## Envelope + * + * Libp2p provides an all-purpose data container called **envelope**. It was created to enable the distribution of verifiable records, which we can prove originated from the addressed peer itself. The envelope includes a signature of the data, so that its authenticity is verified. + * + * This envelope stores a marshaled record implementing the [interface-record](https://github.com/libp2p/js-libp2p/blob/main/packages/interface/src/record/index.ts). These Records are designed to be serialized to bytes and placed inside of the envelopes before being shared with other peers. + * + * You can read further about the envelope in [RFC 0002 - Signed Envelopes](https://github.com/libp2p/specs/blob/master/RFC/0002-signed-envelopes.md). For the original discussion about it you can look at the PR that was used to create it: [libp2p/specs#217](https://github.com/libp2p/specs/pull/217). + * + * @example Creating a peer record + * + * Create an envelope with an instance of an [interface-record](https://github.com/libp2p/js-libp2p/blob/main/packages/interface/src/record/index.ts) implementation and prepare it for being exchanged: + * + * ```TypeScript + * import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record' + * import { generateKeyPair } from '@libp2p/crypto/keys' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' + * + * const privateKey = await generateKeyPair('Ed25519') + * const peerId = peerIdFromPrivateKey(privateKey) + * + * const record = new PeerRecord({ + * peerId, + * // ...other data + * }) + * + * const envelope = await RecordEnvelope.seal(record, privateKey) + * const wireData = envelope.marshal() + * ``` + * + * @example Consuming a peer record + * + * Consume a received envelope `wireData` and transform it back to a record: + * + * ```TypeScript + * import { PeerRecord, RecordEnvelope } from '@libp2p/peer-record' + * + * const wireData = Uint8Array.from([0, 1, 2, 3, 4]) + * const envelope = await RecordEnvelope.openAndCertify(wireData, PeerRecord.DOMAIN) + * + * const record = PeerRecord.createFromProtobuf(envelope.payload) + * ``` + * + * ## Peer Record + * + * All libp2p nodes keep a `PeerStore`, that among other information stores a set of known addresses for each peer, which can come from a variety of sources. + * + * Libp2p peer records were created to enable the distribution of verifiable address records, which we can prove originated from the addressed peer itself. With such guarantees, libp2p is able to prioritize addresses based on their authenticity, with the most strict strategy being to only dial certified addresses (no strategies have been implemented at the time of writing). + * + * A peer record contains the peers' publicly reachable listen addresses, and may be extended in the future to contain additional metadata relevant to routing. It also contains a `seqNumber` field, a timestamp per the spec, so that we can verify the most recent record. + * + * You can read further about the Peer Record in [RFC 0003 - Peer Routing Records](https://github.com/libp2p/specs/blob/master/RFC/0003-routing-records.md). For the original discussion about it you can view the PR that created the RFC: [libp2p/specs#217](https://github.com/libp2p/specs/pull/217). + * + * @example + * + * Create a new Peer Record + * + * ```TypeScript + * import { PeerRecord } from '@libp2p/peer-record' + * import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { generateKeyPair } from '@libp2p/crypto/keys' + * import { multiaddr } from '@multiformats/multiaddr' + * + * const peerId = peerIdFromPrivateKey(await generateKeyPair('Ed25519')) + * + * const record = new PeerRecord({ + * peerId: peerId, + * multiaddrs: [ + * multiaddr('/ip4/...'), + * multiaddr('/ip4/...') + * ] + * }) + * ``` + * + * @example + * + * Create a Peer Record from a protobuf + * + * ```TypeScript + * import { PeerRecord } from '@libp2p/peer-record' + * + * const data = Uint8Array.from([0, 1, 2, 3, 4]) + * const record = PeerRecord.createFromProtobuf(data) + * ``` + * + * ## Libp2p Flows + * + * ### Self Record + * + * Once a libp2p node has started and is listening on a set of multiaddrs, its own peer record can be created. + * + * The identify service is responsible for creating the self record when the identify protocol kicks in for the first time. This record will be stored for future needs of the identify protocol when connecting with other peers. + * + * ### Self record Updates + * + * While creating peer records is fairly trivial, addresses are not static and might be modified at arbitrary times. This can happen via an Address Manager API, or even through AutoRelay/AutoNAT. + * + * When a libp2p node changes its listen addresses, the identify service will be informed. Once that happens, the identify service creates a new self record and stores it. With the new record, the identify push/delta protocol will be used to communicate this change to the connected peers. + * + * ### Subsystem receiving a record + * + * Considering that a node can discover other peers' addresses from a variety of sources, Libp2p PeerStore can differentiate the addresses that were obtained through a signed peer record. + * + * Once a record is received and its signature properly validated, its envelope is stored in the AddressBook in its byte representation. The `seqNumber` remains unmarshaled so that we can quickly compare it against incoming records to determine the most recent record. + * + * The AddressBook Addresses will be updated with the content of the envelope with a certified property. This allows other subsystems to identify the known certified addresses of a peer. + * + * ### Subsystem providing a record + * + * Libp2p subsystems that exchange other peers information will provide the envelope that they received by those peers. As a result, other peers can verify if the envelope was really created by the addressed peer. + * + * When a subsystem wants to provide a record, it will get it from the AddressBook, if it exists. Other subsystems are also able to provide the self record, since it is also stored in the AddressBook. + * + * ## Future Work + * + * - Persistence only considering certified addresses? + * - Peers may not know their own addresses. It's often impossible to automatically infer one's own public address, and peers may need to rely on third party peers to inform them of their observed public addresses. + * - A peer may inadvertently or maliciously sign an address that they do not control. In other words, a signature isn't a guarantee that a given address is valid. + * - Some addresses may be ambiguous. For example, addresses on a private subnet are valid within that subnet but are useless on the public internet. + * - Once all these pieces are in place, we will also need a way to prioritize addresses based on their authenticity, that is, the dialer can prioritize self-certified addresses over addresses from an unknown origin. + * - Modular dialer? (taken from go PR notes) + * - With the modular dialer, users should easily be able to configure precedence. With dialer v1, anything we do to prioritize dials is gonna be spaghetti and adhoc. With the modular dialer, you’d be able to specify the order of dials when instantiating the pipeline. + * - Multiple parallel dials. We already have the issue where new addresses aren't added to existing dials. + */ + +export { RecordEnvelope } from './envelope/index.js' +export type { RecordEnvelopeInit } from './envelope/index.js' +export { PeerRecord } from './peer-record/index.js' +export type { PeerRecordInit } from './peer-record/index.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/consts.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/consts.ts new file mode 100644 index 000000000..fefbeb057 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/consts.ts @@ -0,0 +1,7 @@ +// The domain string used for peer records contained in a Envelope. +export const ENVELOPE_DOMAIN_PEER_RECORD = 'libp2p-peer-record' + +// The type hint used to identify peer records in a Envelope. +// Defined in https://github.com/multiformats/multicodec/blob/master/table.csv +// with name "libp2p-peer-record" +export const ENVELOPE_PAYLOAD_TYPE_PEER_RECORD = Uint8Array.from([3, 1]) diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/index.ts new file mode 100644 index 000000000..ef6688d98 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/index.ts @@ -0,0 +1,105 @@ +import { peerIdFromMultihash } from '@libp2p/peer-id' +import { multiaddr } from '@multiformats/multiaddr' +import * as Digest from 'multiformats/hashes/digest' +import { + ENVELOPE_DOMAIN_PEER_RECORD, + ENVELOPE_PAYLOAD_TYPE_PEER_RECORD +} from './consts.js' +import { PeerRecord as Protobuf } from './peer-record.js' +import { arrayEquals } from './utils.ts' +import type { PeerId } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Uint8ArrayList } from 'uint8arraylist' + +export interface PeerRecordInit { + peerId: PeerId + + /** + * Addresses of the associated peer. + */ + multiaddrs?: Multiaddr[] + + /** + * Monotonically-increasing sequence counter that's used to order PeerRecords in time. + */ + seqNumber?: bigint +} + +/** + * The PeerRecord is used for distributing peer routing records across the network. + * It contains the peer's reachable listen addresses. + */ +export class PeerRecord { + /** + * Unmarshal Peer Record Protobuf + */ + static createFromProtobuf = (buf: Uint8Array | Uint8ArrayList): PeerRecord => { + const peerRecord = Protobuf.decode(buf) + const peerId = peerIdFromMultihash(Digest.decode(peerRecord.peerId)) + const multiaddrs = (peerRecord.addresses ?? []).map((a) => multiaddr(a.multiaddr)) + const seqNumber = peerRecord.seq + + return new PeerRecord({ peerId, multiaddrs, seqNumber }) + } + + static DOMAIN = ENVELOPE_DOMAIN_PEER_RECORD + static CODEC = ENVELOPE_PAYLOAD_TYPE_PEER_RECORD + + public peerId: PeerId + public multiaddrs: Multiaddr[] + public seqNumber: bigint + public domain = PeerRecord.DOMAIN + public codec = PeerRecord.CODEC + private marshaled?: Uint8Array + + constructor (init: PeerRecordInit) { + const { peerId, multiaddrs, seqNumber } = init + + this.peerId = peerId + this.multiaddrs = multiaddrs ?? [] + this.seqNumber = seqNumber ?? BigInt(Date.now()) + } + + /** + * Marshal a record to be used in an envelope + */ + marshal (): Uint8Array { + if (this.marshaled == null) { + this.marshaled = Protobuf.encode({ + peerId: this.peerId.toMultihash().bytes, + seq: BigInt(this.seqNumber), + addresses: this.multiaddrs.map((m) => ({ + multiaddr: m.bytes + })) + }) + } + + return this.marshaled + } + + /** + * Returns true if `this` record equals the `other` + */ + equals (other: unknown): boolean { + if (!(other instanceof PeerRecord)) { + return false + } + + // Validate PeerId + if (!this.peerId.equals(other.peerId)) { + return false + } + + // Validate seqNumber + if (this.seqNumber !== other.seqNumber) { + return false + } + + // Validate multiaddrs + if (!arrayEquals(this.multiaddrs, other.multiaddrs)) { + return false + } + + return true + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/peer-record.proto b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/peer-record.proto new file mode 100644 index 000000000..6b740dc80 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/peer-record.proto @@ -0,0 +1,18 @@ +syntax = "proto3"; + +message PeerRecord { + // AddressInfo is a wrapper around a binary multiaddr. It is defined as a + // separate message to allow us to add per-address metadata in the future. + message AddressInfo { + bytes multiaddr = 1; + } + + // peer_id contains a libp2p peer id in its binary representation. + bytes peer_id = 1; + + // seq contains a monotonically-increasing sequence counter to order PeerRecords in time. + uint64 seq = 2; + + // addresses is a list of public listen addresses for the peer. + repeated AddressInfo addresses = 3; +} \ No newline at end of file diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/peer-record.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/peer-record.ts new file mode 100644 index 000000000..a607de965 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/peer-record.ts @@ -0,0 +1,154 @@ +import { decodeMessage, encodeMessage, MaxLengthError, message } from 'protons-runtime' +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' +import type { Codec, DecodeOptions } from 'protons-runtime' +import type { Uint8ArrayList } from 'uint8arraylist' + +export interface PeerRecord { + peerId: Uint8Array + seq: bigint + addresses: PeerRecord.AddressInfo[] +} + +export namespace PeerRecord { + export interface AddressInfo { + multiaddr: Uint8Array + } + + export namespace AddressInfo { + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.multiaddr != null && obj.multiaddr.byteLength > 0)) { + w.uint32(10) + w.bytes(obj.multiaddr) + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + multiaddr: uint8ArrayAlloc(0) + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.multiaddr = reader.bytes() + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }) + } + + return _codec + } + + export const encode = (obj: Partial): Uint8Array => { + return encodeMessage(obj, AddressInfo.codec()) + } + + export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): AddressInfo => { + return decodeMessage(buf, AddressInfo.codec(), opts) + } + } + + let _codec: Codec + + export const codec = (): Codec => { + if (_codec == null) { + _codec = message((obj, w, opts = {}) => { + if (opts.lengthDelimited !== false) { + w.fork() + } + + if ((obj.peerId != null && obj.peerId.byteLength > 0)) { + w.uint32(10) + w.bytes(obj.peerId) + } + + if ((obj.seq != null && obj.seq !== 0n)) { + w.uint32(16) + w.uint64(obj.seq) + } + + if (obj.addresses != null) { + for (const value of obj.addresses) { + w.uint32(26) + PeerRecord.AddressInfo.codec().encode(value, w) + } + } + + if (opts.lengthDelimited !== false) { + w.ldelim() + } + }, (reader, length, opts = {}) => { + const obj: any = { + peerId: uint8ArrayAlloc(0), + seq: 0n, + addresses: [] + } + + const end = length == null ? reader.len : reader.pos + length + + while (reader.pos < end) { + const tag = reader.uint32() + + switch (tag >>> 3) { + case 1: { + obj.peerId = reader.bytes() + break + } + case 2: { + obj.seq = reader.uint64() + break + } + case 3: { + if (opts.limits?.addresses != null && obj.addresses.length === opts.limits.addresses) { + throw new MaxLengthError('Decode error - map field "addresses" had too many elements') + } + + obj.addresses.push(PeerRecord.AddressInfo.codec().decode(reader, reader.uint32(), { + limits: opts.limits?.addresses$ + })) + break + } + default: { + reader.skipType(tag & 7) + break + } + } + } + + return obj + }) + } + + return _codec + } + + export const encode = (obj: Partial): Uint8Array => { + return encodeMessage(obj, PeerRecord.codec()) + } + + export const decode = (buf: Uint8Array | Uint8ArrayList, opts?: DecodeOptions): PeerRecord => { + return decodeMessage(buf, PeerRecord.codec(), opts) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/utils.ts new file mode 100644 index 000000000..91fb4f333 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/src/peer-record/utils.ts @@ -0,0 +1,15 @@ +/** + * Verify if two arrays of non primitive types with the "equals" function are equal. + * Compatible with multiaddr, peer-id and others. + */ +export function arrayEquals (a: any[], b: any[]): boolean { + const sort = (a: any, b: any): number => a.toString().localeCompare(b.toString()) + + if (a.length !== b.length) { + return false + } + + b.sort(sort) + + return a.sort(sort).every((item, index) => b[index].equals(item)) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/peer-record/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/README.md new file mode 100644 index 000000000..7dc3cef95 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/README.md @@ -0,0 +1,103 @@ +# @libp2p/perf + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> Implementation of Perf Protocol + +# About + + + +The Perf service implements the [perf protocol](https://github.com/libp2p/specs/blob/master/perf/perf.md), which can be used to measure transfer performance within and across libp2p implementations. + +## Example + +```typescript +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { tcp } from '@libp2p/tcp' +import { createLibp2p, type Libp2p } from 'libp2p' +import { plaintext } from '@libp2p/plaintext' +import { perf, type Perf } from '@libp2p/perf' + +const ONE_MEG = 1024 * 1024 +const UPLOAD_BYTES = ONE_MEG * 1024 +const DOWNLOAD_BYTES = ONE_MEG * 1024 + +async function createNode (): Promise> { + return createLibp2p({ + addresses: { + listen: [ + '/ip4/0.0.0.0/tcp/0' + ] + }, + transports: [ + tcp() + ], + connectionEncrypters: [ + noise(), plaintext() + ], + streamMuxers: [ + yamux() + ], + services: { + perf: perf() + } + }) +} + +const libp2p1 = await createNode() +const libp2p2 = await createNode() + +for await (const output of libp2p1.services.perf.measurePerformance(libp2p2.getMultiaddrs()[0], UPLOAD_BYTES, DOWNLOAD_BYTES)) { + console.info(output) +} + +await libp2p1.stop() +await libp2p2.stop() +``` + +# Install + +```console +$ npm i @libp2p/perf +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/protocol-perf/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/protocol-perf/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/package.json new file mode 100644 index 000000000..987dbf630 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/package.json @@ -0,0 +1,56 @@ +{ + "name": "@libp2p/perf", + "version": "4.0.46", + "description": "Implementation of Perf Protocol", + "author": "@maschad / @marcopolo", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/protocol-perf#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "start": "node dist/src/main.js", + "build": "aegir build", + "test": "aegir test", + "clean": "aegir clean", + "lint": "aegir lint", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check" + }, + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/interface-internal": "^2.3.18", + "@multiformats/multiaddr": "^12.4.4", + "it-pushable": "^3.2.3", + "race-event": "^1.6.1", + "uint8arraylist": "^2.4.8" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/constants.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/constants.ts new file mode 100644 index 000000000..395cd04f8 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/constants.ts @@ -0,0 +1,5 @@ +export const PROTOCOL_NAME = '/perf/1.0.0' +export const WRITE_BLOCK_SIZE = 64 << 10 +export const MAX_INBOUND_STREAMS = 1 +export const MAX_OUTBOUND_STREAMS = 1 +export const RUN_ON_LIMITED_CONNECTION = false diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/index.ts new file mode 100644 index 000000000..4965614f5 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/index.ts @@ -0,0 +1,105 @@ +/** + * @packageDocumentation + * + * The {@link Perf} service implements the [perf protocol](https://github.com/libp2p/specs/blob/master/perf/perf.md), which can be used to measure transfer performance within and across libp2p implementations. + * + * @example + * + * ```typescript + * import { noise } from '@chainsafe/libp2p-noise' + * import { yamux } from '@chainsafe/libp2p-yamux' + * import { tcp } from '@libp2p/tcp' + * import { createLibp2p, type Libp2p } from 'libp2p' + * import { plaintext } from '@libp2p/plaintext' + * import { perf, type Perf } from '@libp2p/perf' + * + * const ONE_MEG = 1024 * 1024 + * const UPLOAD_BYTES = ONE_MEG * 1024 + * const DOWNLOAD_BYTES = ONE_MEG * 1024 + * + * async function createNode (): Promise> { + * return createLibp2p({ + * addresses: { + * listen: [ + * '/ip4/0.0.0.0/tcp/0' + * ] + * }, + * transports: [ + * tcp() + * ], + * connectionEncrypters: [ + * noise(), plaintext() + * ], + * streamMuxers: [ + * yamux() + * ], + * services: { + * perf: perf() + * } + * }) + * } + * + * const libp2p1 = await createNode() + * const libp2p2 = await createNode() + * + * for await (const output of libp2p1.services.perf.measurePerformance(libp2p2.getMultiaddrs()[0], UPLOAD_BYTES, DOWNLOAD_BYTES)) { + * console.info(output) + * } + * + * await libp2p1.stop() + * await libp2p2.stop() + * ``` + */ + +import { Perf as PerfClass } from './perf-service.js' +import type { AbortOptions, ComponentLogger } from '@libp2p/interface' +import type { ConnectionManager, Registrar } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' + +export interface PerfOptions extends AbortOptions { + /** + * By default measuring perf should include the time it takes to establish a + * connection, so a new connection will be opened for every performance run. + * + * To override this and re-use an existing connection if one is present, pass + * `true` here. + * + * @default false + */ + reuseExistingConnection?: boolean +} + +export interface Perf { + measurePerformance(multiaddr: Multiaddr, sendBytes: number, recvBytes: number, options?: PerfOptions): AsyncGenerator +} + +export interface PerfOutput { + type: 'connection' | 'stream' | 'intermediary' | 'final' + timeSeconds: number + uploadBytes: number + downloadBytes: number +} + +export interface PerfInit { + protocolName?: string + maxInboundStreams?: number + maxOutboundStreams?: number + runOnLimitedConnection?: boolean + + /** + * Data sent/received will be sent in chunks of this size + * + * @default 65536 + */ + writeBlockSize?: number +} + +export interface PerfComponents { + registrar: Registrar + connectionManager: ConnectionManager + logger: ComponentLogger +} + +export function perf (init: PerfInit = {}): (components: PerfComponents) => Perf { + return (components) => new PerfClass(components, init) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/perf-service.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/perf-service.ts new file mode 100644 index 000000000..4fadceea1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/src/perf-service.ts @@ -0,0 +1,231 @@ +import { pushable } from 'it-pushable' +import { raceEvent } from 'race-event' +import { Uint8ArrayList } from 'uint8arraylist' +import { MAX_INBOUND_STREAMS, MAX_OUTBOUND_STREAMS, PROTOCOL_NAME, RUN_ON_LIMITED_CONNECTION, WRITE_BLOCK_SIZE } from './constants.js' +import type { PerfOptions, PerfOutput, PerfComponents, PerfInit, Perf as PerfInterface } from './index.js' +import type { Connection, Logger, Startable, Stream } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +export class Perf implements Startable, PerfInterface { + private readonly log: Logger + public readonly protocol: string + private readonly components: PerfComponents + private started: boolean + private readonly buf: ArrayBuffer + private readonly writeBlockSize: number + private readonly maxInboundStreams: number + private readonly maxOutboundStreams: number + private readonly runOnLimitedConnection: boolean + + constructor (components: PerfComponents, init: PerfInit = {}) { + this.components = components + this.log = components.logger.forComponent('libp2p:perf') + this.started = false + this.protocol = init.protocolName ?? PROTOCOL_NAME + this.writeBlockSize = init.writeBlockSize ?? WRITE_BLOCK_SIZE + this.buf = new ArrayBuffer(this.writeBlockSize) + this.maxInboundStreams = init.maxInboundStreams ?? MAX_INBOUND_STREAMS + this.maxOutboundStreams = init.maxOutboundStreams ?? MAX_OUTBOUND_STREAMS + this.runOnLimitedConnection = init.runOnLimitedConnection ?? RUN_ON_LIMITED_CONNECTION + this.handleMessage = this.handleMessage.bind(this) + } + + readonly [Symbol.toStringTag] = '@libp2p/perf' + + async start (): Promise { + await this.components.registrar.handle(this.protocol, this.handleMessage, { + maxInboundStreams: this.maxInboundStreams, + maxOutboundStreams: this.maxOutboundStreams, + runOnLimitedConnection: this.runOnLimitedConnection + }) + this.started = true + } + + async stop (): Promise { + await this.components.registrar.unhandle(this.protocol) + this.started = false + } + + isStarted (): boolean { + return this.started + } + + async handleMessage (stream: Stream): Promise { + try { + const writeBlockSize = this.writeBlockSize + + let bytesToSendBack: number | undefined + + for await (const buf of stream) { + if (bytesToSendBack == null) { + const list = new Uint8ArrayList(buf) + // downcast 64 to 52 bits to avoid bigint arithmetic performance penalty + bytesToSendBack = Number(list.getBigUint64(0, false)) + } + + // Ingest all the data and wait for the read side to close + } + + if (bytesToSendBack == null) { + throw new Error('bytesToSendBack was not set') + } + + const uint8Buf = new Uint8Array(this.buf, 0, this.buf.byteLength) + + while (bytesToSendBack > 0) { + let toSend: number = writeBlockSize + if (toSend > bytesToSendBack) { + toSend = bytesToSendBack + } + + bytesToSendBack = bytesToSendBack - toSend + const buf = uint8Buf.subarray(0, toSend) + + const sendMore = stream.send(buf) + + if (!sendMore) { + await raceEvent(stream, 'drain') + } + } + + await stream.closeWrite() + } catch (err: any) { + stream.abort(err) + } + } + + async * measurePerformance (ma: Multiaddr, sendBytes: number, receiveBytes: number, options: PerfOptions = {}): AsyncGenerator { + const uint8Buf = new Uint8Array(this.buf) + const writeBlockSize = this.writeBlockSize + + const initialStartTime = Date.now() + let lastReportedTime = Date.now() + const connection = await this.components.connectionManager.openConnection(ma, { + ...options, + force: options.reuseExistingConnection !== true + }) + + const log = connection.log.newScope('perf') + + log('opened connection after %d ms', Date.now() - lastReportedTime) + lastReportedTime = Date.now() + + const stream = await connection.newStream(this.protocol, options) + + log('opened stream after %d ms', Date.now() - lastReportedTime) + lastReportedTime = Date.now() + + let lastAmountOfBytesSent = 0 + let totalBytesSent = 0 + const uploadStart = Date.now() + + // tell the remote how many bytes we will send. Up cast to 64 bit number + // as if we send as ui32 we limit total transfer size to 4GB + const view = new DataView(this.buf) + view.setBigUint64(0, BigInt(receiveBytes), false) + + log('sending %i bytes to %p', sendBytes, connection.remotePeer) + + try { + const output = pushable({ + objectMode: true + }) + + Promise.resolve().then(async () => { + const sendMore = stream.send(uint8Buf.subarray(0, 8)) + + if (!sendMore) { + await raceEvent(stream, 'drain') + } + + while (sendBytes > 0) { + let toSend: number = writeBlockSize + + if (toSend > sendBytes) { + toSend = sendBytes + } + + const sendMore = stream.send(uint8Buf.subarray(0, toSend)) + + if (!sendMore) { + await raceEvent(stream, 'drain') + } + + sendBytes -= toSend + + if (Date.now() - lastReportedTime > 1000) { + output.push({ + type: 'intermediary', + timeSeconds: (Date.now() - lastReportedTime) / 1000, + uploadBytes: lastAmountOfBytesSent, + downloadBytes: 0 + }) + + // record last reported time after `console.log` because it can + // affect benchmark timings + lastReportedTime = Date.now() + lastAmountOfBytesSent = 0 + } + + lastAmountOfBytesSent += toSend + totalBytesSent += toSend + } + + output.end() + }) + .catch(err => { + output.end(err) + }) + + yield * output + + log('upload complete after %d ms', Date.now() - uploadStart) + + await stream.closeWrite(options) + + // Read the received bytes + let lastAmountOfBytesReceived = 0 + lastReportedTime = Date.now() + let totalBytesReceived = 0 + const downloadStart = Date.now() + + for await (const buf of stream) { + if (Date.now() - lastReportedTime > 1000) { + yield { + type: 'intermediary', + timeSeconds: (Date.now() - lastReportedTime) / 1000, + uploadBytes: 0, + downloadBytes: lastAmountOfBytesReceived + } + + // record last reported time after `console.log` because it can + // affect benchmark timings + lastReportedTime = Date.now() + lastAmountOfBytesReceived = 0 + } + + lastAmountOfBytesReceived += buf.byteLength + totalBytesReceived += buf.byteLength + } + + log('download complete after %d ms', Date.now() - downloadStart) + + if (totalBytesReceived !== receiveBytes) { + throw new Error(`Expected to receive ${receiveBytes} bytes, but received ${totalBytesReceived}`) + } + + yield { + type: 'final', + timeSeconds: (Date.now() - initialStartTime) / 1000, + uploadBytes: totalBytesSent, + downloadBytes: totalBytesReceived + } + + log('performed %s to %p', this.protocol, connection.remotePeer) + } catch (err: any) { + log('error sending %d/%d bytes to %p: %s', totalBytesSent, sendBytes, connection.remotePeer, err) + stream.abort(err) + throw err + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/protocol-perf/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/.aegir.js b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/.aegir.js new file mode 100644 index 000000000..7ecc20b05 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/.aegir.js @@ -0,0 +1,7 @@ + +/** @type {import('aegir/types').PartialOptions} */ +export default { + build: { + bundlesizeMax: '9.5kB' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/README.md new file mode 100644 index 000000000..f3b3ba4c8 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/README.md @@ -0,0 +1,127 @@ +# @chainsafe/libp2p-yamux + +[![codecov](https://img.shields.io/codecov/c/github/ChainSafe/js-libp2p-yamux.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/js-libp2p-yamux) +[![CI](https://img.shields.io/github/actions/workflow/status/ChainSafe/js-libp2p-yamux/js-test-and-release.yml?branch=master\&style=flat-square)](https://github.com/ChainSafe/js-libp2p-yamux/actions/workflows/js-test-and-release.yml?query=branch%3Amaster) + +> Yamux stream multiplexer for libp2p + +# About + + + +This module is a JavaScript implementation of [Yamux from Hashicorp](https://github.com/hashicorp/yamux/blob/master/spec.md) designed to be used with [js-libp2p](https://github.com/libp2p/js-libp2p). + +## Example - Configure libp2p with Yamux + +```typescript +import { createLibp2p } from 'libp2p' +import { yamux } from '@chainsafe/libp2p-yamux' + +const node = await createLibp2p({ + // ... other options + streamMuxers: [ + yamux() + ] +}) +``` + +## Example - Using the low-level API + +```js +import { yamux } from '@chainsafe/libp2p-yamux' +import { pipe } from 'it-pipe' +import { duplexPair } from 'it-pair/duplex' +import all from 'it-all' + +// Connect two yamux muxers to demo basic stream multiplexing functionality + +const clientMuxer = yamux({ + client: true, + onIncomingStream: stream => { + // echo data on incoming streams + pipe(stream, stream) + }, + onStreamEnd: stream => { + // do nothing + } +})() + +const serverMuxer = yamux({ + client: false, + onIncomingStream: stream => { + // echo data on incoming streams + pipe(stream, stream) + }, + onStreamEnd: stream => { + // do nothing + } +})() + +// `p` is our "connections", what we use to connect the two sides +// In a real application, a connection is usually to a remote computer +const p = duplexPair() + +// connect the muxers together +pipe(p[0], clientMuxer, p[0]) +pipe(p[1], serverMuxer, p[1]) + +// now either side can open streams +const stream0 = clientMuxer.newStream() +const stream1 = serverMuxer.newStream() + +// Send some data to the other side +const encoder = new TextEncoder() +const data = [encoder.encode('hello'), encoder.encode('world')] +pipe(data, stream0) + +// Receive data back +const result = await pipe(stream0, all) + +// close a stream +stream1.close() + +// close the muxer +clientMuxer.close() +``` + +# Install + +```console +$ npm i @chainsafe/libp2p-yamux +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/ChainSafe/js-libp2p-yamux/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/ChainSafe/js-libp2p-yamux/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/package.json new file mode 100644 index 000000000..f32e68170 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/package.json @@ -0,0 +1,179 @@ +{ + "name": "@chainsafe/libp2p-yamux", + "version": "7.0.4", + "description": "Yamux stream multiplexer for libp2p", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/ChainSafe/js-libp2p-yamux#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/ChainSafe/js-libp2p-yamux.git" + }, + "bugs": { + "url": "https://github.com/ChainSafe/js-libp2p-yamux/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "IPFS", + "libp2p", + "multiplexer", + "muxer", + "stream" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "typesVersions": { + "*": { + "*": [ + "*", + "dist/*", + "dist/src/*", + "dist/src/*/index" + ], + "src/*": [ + "*", + "dist/*", + "dist/src/*", + "dist/src/*/index" + ] + } + }, + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + }, + "./config": { + "types": "./dist/src/config.d.ts", + "import": "./dist/src/config.js" + }, + "./stream": { + "types": "./dist/src/stream.d.ts", + "import": "./dist/src/stream.js" + } + }, + "release": { + "branches": [ + "master" + ], + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "preset": "conventionalcommits", + "releaseRules": [ + { + "breaking": true, + "release": "major" + }, + { + "revert": true, + "release": "patch" + }, + { + "type": "feat", + "release": "minor" + }, + { + "type": "fix", + "release": "patch" + }, + { + "type": "docs", + "release": "patch" + }, + { + "type": "test", + "release": "patch" + }, + { + "type": "deps", + "release": "patch" + }, + { + "scope": "no-release", + "release": false + } + ] + } + ], + [ + "@semantic-release/release-notes-generator", + { + "preset": "conventionalcommits", + "presetConfig": { + "types": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "chore", + "section": "Trivial Changes" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "deps", + "section": "Dependencies" + }, + { + "type": "test", + "section": "Tests" + } + ] + } + } + ], + "@semantic-release/changelog", + "@semantic-release/npm", + "@semantic-release/github", + [ + "@semantic-release/git", + { + "assets": [ + "CHANGELOG.md", + "package.json" + ] + } + ] + ] + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "benchmark": "benchmark dist/test/bench/*.bench.js --timeout 400000", + "build": "aegir build", + "test": "aegir test", + "test:chrome": "aegir test -t browser", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "release": "aegir release", + "docs": "aegir docs" + }, + "dependencies": { + "@libp2p/interface": "^2.0.0", + "@libp2p/utils": "^6.0.0", + "race-signal": "^1.1.3", + "uint8arraylist": "^2.4.8" + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/config.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/config.ts new file mode 100644 index 000000000..2cd9c5420 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/config.ts @@ -0,0 +1,81 @@ +import { InvalidParametersError } from '@libp2p/interface' +import { INITIAL_STREAM_WINDOW, MAX_STREAM_WINDOW } from './constants.js' + +// TOOD use config items or delete them +export interface Config { + /** + * Used to do periodic keep alive messages using a ping. + */ + enableKeepAlive: boolean + + /** + * How often to perform the keep alive + * + * measured in milliseconds + */ + keepAliveInterval: number + + /** + * Maximum number of concurrent inbound streams that we accept. + * If the peer tries to open more streams, those will be reset immediately. + */ + maxInboundStreams: number + + /** + * Maximum number of concurrent outbound streams that we accept. + * If the application tries to open more streams, the call to `newStream` will throw + */ + maxOutboundStreams: number + + /** + * Used to control the initial window size that we allow for a stream. + * + * measured in bytes + */ + initialStreamWindowSize: number + + /** + * Used to control the maximum window size that we allow for a stream. + */ + maxStreamWindowSize: number + + /** + * Maximum size of a message that we'll send on a stream. + * This ensures that a single stream doesn't hog a connection. + */ + maxMessageSize: number +} + +export const defaultConfig: Config = { + enableKeepAlive: true, + keepAliveInterval: 30_000, + maxInboundStreams: 1_000, + maxOutboundStreams: 1_000, + initialStreamWindowSize: INITIAL_STREAM_WINDOW, + maxStreamWindowSize: MAX_STREAM_WINDOW, + maxMessageSize: 64 * 1024 +} + +export function verifyConfig (config: Config): void { + if (config.keepAliveInterval <= 0) { + throw new InvalidParametersError('keep-alive interval must be positive') + } + if (config.maxInboundStreams < 0) { + throw new InvalidParametersError('max inbound streams must be larger or equal 0') + } + if (config.maxOutboundStreams < 0) { + throw new InvalidParametersError('max outbound streams must be larger or equal 0') + } + if (config.initialStreamWindowSize < INITIAL_STREAM_WINDOW) { + throw new InvalidParametersError('InitialStreamWindowSize must be larger or equal 256 kB') + } + if (config.maxStreamWindowSize < config.initialStreamWindowSize) { + throw new InvalidParametersError('MaxStreamWindowSize must be larger than the InitialStreamWindowSize') + } + if (config.maxStreamWindowSize > 2 ** 32 - 1) { + throw new InvalidParametersError('MaxStreamWindowSize must be less than equal MAX_UINT32') + } + if (config.maxMessageSize < 1024) { + throw new InvalidParametersError('MaxMessageSize must be greater than a kilobyte') + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/constants.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/constants.ts new file mode 100644 index 000000000..546b38f16 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/constants.ts @@ -0,0 +1,25 @@ +// Protocol violation errors + +import { BothClientsError, DecodeInvalidVersionError, InvalidFrameError, NotMatchingPingError, ReceiveWindowExceededError, StreamAlreadyExistsError, UnrequestedPingError } from './errors.js' + +export const PROTOCOL_ERRORS = new Set([ + InvalidFrameError.name, + UnrequestedPingError.name, + NotMatchingPingError.name, + StreamAlreadyExistsError.name, + DecodeInvalidVersionError.name, + BothClientsError.name, + ReceiveWindowExceededError.name +]) + +/** + * INITIAL_STREAM_WINDOW is the initial stream window size. + * + * Not an implementation choice, this is defined in the specification + */ +export const INITIAL_STREAM_WINDOW = 256 * 1024 + +/** + * Default max stream window + */ +export const MAX_STREAM_WINDOW = 16 * 1024 * 1024 diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/decode.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/decode.ts new file mode 100644 index 000000000..f18c29b93 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/decode.ts @@ -0,0 +1,103 @@ +import { Uint8ArrayList } from 'uint8arraylist' +import { InvalidFrameError } from './errors.js' +import { FrameType, HEADER_LENGTH, YAMUX_VERSION } from './frame.js' +import type { FrameHeader } from './frame.js' + +export interface Frame { + header: FrameHeader + data?: Uint8ArrayList +} + +export interface DataFrame { + header: FrameHeader + data: Uint8ArrayList +} + +export function isDataFrame (frame: Frame): frame is DataFrame { + return frame.header.type === FrameType.Data && frame.data !== null +} + +// used to bitshift in decoding +// native bitshift can overflow into a negative number, so we bitshift by multiplying by a power of 2 +const twoPow24 = 2 ** 24 + +/** + * Decode a header from the front of a buffer + * + * @param data - Assumed to have enough bytes for a header + */ +export function decodeHeader (data: Uint8Array): FrameHeader { + if (data[0] !== YAMUX_VERSION) { + throw new InvalidFrameError('Invalid frame version') + } + + return { + type: data[1], + flag: (data[2] << 8) + data[3], + streamID: (data[4] * twoPow24) + (data[5] << 16) + (data[6] << 8) + data[7], + length: (data[8] * twoPow24) + (data[9] << 16) + (data[10] << 8) + data[11] + } +} + +/** + * Decodes yamux frames from a source + */ +export class Decoder { + /** Buffer for in-progress frames */ + private readonly buffer: Uint8ArrayList + + constructor () { + this.buffer = new Uint8ArrayList() + } + + /** + * Emits frames from the decoder source. + * + * Note: If `readData` is emitted, it _must_ be called before the next iteration + * Otherwise an error is thrown + */ + * emitFrames (buf: Uint8Array | Uint8ArrayList): Generator { + this.buffer.append(buf) + + // Loop to consume as many bytes from the buffer as possible + // Eg: when a single chunk contains several frames + while (true) { + const frame = this.readFrame() + + if (frame === undefined) { + break + } + + yield frame + } + } + + private readFrame (): Frame | undefined { + let frameSize = HEADER_LENGTH + + if (this.buffer.byteLength < HEADER_LENGTH) { + // not enough data yet + return + } + + const header = decodeHeader(this.buffer.subarray(0, HEADER_LENGTH)) + + if (header.type === FrameType.Data) { + frameSize += header.length + + if (this.buffer.byteLength < frameSize) { + // not enough data yet + return + } + + const data = this.buffer.sublist(HEADER_LENGTH, frameSize) + this.buffer.consume(frameSize) + + return { header, data } + } + + this.buffer.consume(frameSize) + + return { header } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/encode.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/encode.ts new file mode 100644 index 000000000..6353c0091 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/encode.ts @@ -0,0 +1,26 @@ +import { HEADER_LENGTH } from './frame.js' +import type { FrameHeader } from './frame.js' + +export function encodeHeader (header: FrameHeader): Uint8Array { + const frame = new Uint8Array(HEADER_LENGTH) + + // always assume version 0 + // frameView.setUint8(0, header.version) + + frame[1] = header.type + + frame[2] = header.flag >>> 8 + frame[3] = header.flag + + frame[4] = header.streamID >>> 24 + frame[5] = header.streamID >>> 16 + frame[6] = header.streamID >>> 8 + frame[7] = header.streamID + + frame[8] = header.length >>> 24 + frame[9] = header.length >>> 16 + frame[10] = header.length >>> 8 + frame[11] = header.length + + return frame +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/errors.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/errors.ts new file mode 100644 index 000000000..953b020bb --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/errors.ts @@ -0,0 +1,89 @@ +import { GoAwayCode } from './frame.ts' + +export class ProtocolError extends Error { + static name = 'ProtocolError' + + public reason: GoAwayCode + + constructor (message: string, reason: GoAwayCode) { + super(message) + this.name = 'ProtocolError' + this.reason = reason + } +} + +export function isProtocolError (err?: any): err is ProtocolError { + return err?.reason !== null +} + +export class InvalidFrameError extends ProtocolError { + static name = 'InvalidFrameError' + + constructor (message = 'The frame was invalid') { + super(message, GoAwayCode.ProtocolError) + this.name = 'InvalidFrameError' + } +} + +export class UnrequestedPingError extends ProtocolError { + static name = 'UnrequestedPingError' + + constructor (message = 'Unrequested ping error') { + super(message, GoAwayCode.ProtocolError) + this.name = 'UnrequestedPingError' + } +} + +export class NotMatchingPingError extends ProtocolError { + static name = 'NotMatchingPingError' + + constructor (message = 'Unrequested ping error') { + super(message, GoAwayCode.ProtocolError) + this.name = 'NotMatchingPingError' + } +} + +export class InvalidStateError extends Error { + static name = 'InvalidStateError' + + constructor (message = 'Invalid state') { + super(message) + this.name = 'InvalidStateError' + } +} + +export class StreamAlreadyExistsError extends ProtocolError { + static name = 'StreamAlreadyExistsError' + + constructor (message = 'Stream already exists') { + super(message, GoAwayCode.ProtocolError) + this.name = 'StreamAlreadyExistsError' + } +} + +export class DecodeInvalidVersionError extends ProtocolError { + static name = 'DecodeInvalidVersionError' + + constructor (message = 'Decode invalid version') { + super(message, GoAwayCode.ProtocolError) + this.name = 'DecodeInvalidVersionError' + } +} + +export class BothClientsError extends ProtocolError { + static name = 'BothClientsError' + + constructor (message = 'Both clients') { + super(message, GoAwayCode.ProtocolError) + this.name = 'BothClientsError' + } +} + +export class ReceiveWindowExceededError extends ProtocolError { + static name = 'ReceiveWindowExceededError' + + constructor (message = 'Receive window exceeded') { + super(message, GoAwayCode.ProtocolError) + this.name = 'ReceiveWindowExceededError' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/frame.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/frame.ts new file mode 100644 index 000000000..4d61912eb --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/frame.ts @@ -0,0 +1,64 @@ +export enum FrameType { + /** Used to transmit data. May transmit zero length payloads depending on the flags. */ + Data = 0x0, + /** Used to updated the senders receive window size. This is used to implement per-session flow control. */ + WindowUpdate = 0x1, + /** Used to measure RTT. It can also be used to heart-beat and do keep-alives over TCP. */ + Ping = 0x2, + /** Used to close a session. */ + GoAway = 0x3 +} + +export enum Flag { + /** Signals the start of a new stream. May be sent with a data or window update message. Also sent with a ping to indicate outbound. */ + SYN = 0x1, + /** Acknowledges the start of a new stream. May be sent with a data or window update message. Also sent with a ping to indicate response. */ + ACK = 0x2, + /** Performs a half-close of a stream. May be sent with a data message or window update. */ + FIN = 0x4, + /** Reset a stream immediately. May be sent with a data or window update message. */ + RST = 0x8 +} + +const flagCodes = Object.values(Flag).filter((x) => typeof x !== 'string') as Flag[] + +export const YAMUX_VERSION = 0 + +export enum GoAwayCode { + NormalTermination = 0x0, + ProtocolError = 0x1, + InternalError = 0x2 +} + +export const HEADER_LENGTH = 12 + +export interface FrameHeader { + /** + * The version field is used for future backward compatibility. + * At the current time, the field is always set to 0, to indicate the initial version. + */ + version?: number + /** The type field is used to switch the frame message type. */ + type: FrameType + /** The flags field is used to provide additional information related to the message type. */ + flag: number + /** + * The StreamID field is used to identify the logical stream the frame is addressing. + * The client side should use odd ID's, and the server even. + * This prevents any collisions. Additionally, the 0 ID is reserved to represent the session. + */ + streamID: number + /** + * The meaning of the length field depends on the message type: + * Data - provides the length of bytes following the header + * Window update - provides a delta update to the window size + * Ping - Contains an opaque value, echoed back + * Go Away - Contains an error code + */ + length: number +} + +export function stringifyHeader (header: FrameHeader): string { + const flags = flagCodes.filter(f => (header.flag & f) === f).map(f => Flag[f]).join('|') + return `streamID=${header.streamID} type=${FrameType[header.type]} flag=${flags} length=${header.length}` +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/index.ts new file mode 100644 index 000000000..31298d6a3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/index.ts @@ -0,0 +1,90 @@ +/** + * @packageDocumentation + * + * This module is a JavaScript implementation of [Yamux from Hashicorp](https://github.com/hashicorp/yamux/blob/master/spec.md) designed to be used with [js-libp2p](https://github.com/libp2p/js-libp2p). + * + * @example Configure libp2p with Yamux + * + * ```typescript + * import { createLibp2p } from 'libp2p' + * import { yamux } from '@chainsafe/libp2p-yamux' + * + * const node = await createLibp2p({ + * // ... other options + * streamMuxers: [ + * yamux() + * ] + * }) + * ``` + * + * @example Using the low-level API + * + * ```js + * import { yamux } from '@chainsafe/libp2p-yamux' + * import { pipe } from 'it-pipe' + * import { duplexPair } from 'it-pair/duplex' + * import all from 'it-all' + * + * // Connect two yamux muxers to demo basic stream multiplexing functionality + * + * const clientMuxer = yamux({ + * client: true, + * onIncomingStream: stream => { + * // echo data on incoming streams + * pipe(stream, stream) + * }, + * onStreamEnd: stream => { + * // do nothing + * } + * })() + * + * const serverMuxer = yamux({ + * client: false, + * onIncomingStream: stream => { + * // echo data on incoming streams + * pipe(stream, stream) + * }, + * onStreamEnd: stream => { + * // do nothing + * } + * })() + * + * // `p` is our "connections", what we use to connect the two sides + * // In a real application, a connection is usually to a remote computer + * const p = duplexPair() + * + * // connect the muxers together + * pipe(p[0], clientMuxer, p[0]) + * pipe(p[1], serverMuxer, p[1]) + * + * // now either side can open streams + * const stream0 = clientMuxer.newStream() + * const stream1 = serverMuxer.newStream() + * + * // Send some data to the other side + * const encoder = new TextEncoder() + * const data = [encoder.encode('hello'), encoder.encode('world')] + * pipe(data, stream0) + * + * // Receive data back + * const result = await pipe(stream0, all) + * + * // close a stream + * stream1.close() + * + * // close the muxer + * clientMuxer.close() + * ``` + */ + +import { Yamux } from './muxer.js' +import type { YamuxMuxer, YamuxMuxerInit } from './muxer.js' +import type { StreamMuxerFactory } from '@libp2p/interface' + +export { GoAwayCode } from './frame.js' +export type { FrameHeader, FrameType } from './frame.js' +export type { YamuxMuxerInit } + +export function yamux (init: YamuxMuxerInit = {}): () => StreamMuxerFactory { + return () => new Yamux(init) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/muxer.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/muxer.ts new file mode 100644 index 000000000..3cbb94bf2 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/muxer.ts @@ -0,0 +1,487 @@ +import { InvalidParametersError, MuxerClosedError, TooManyOutboundProtocolStreamsError, serviceCapabilities, setMaxListeners } from '@libp2p/interface' +import { AbstractStreamMuxer, repeatingTask, type RepeatingTask } from '@libp2p/utils' +import { raceSignal } from 'race-signal' +import { Uint8ArrayList } from 'uint8arraylist' +import { defaultConfig, verifyConfig } from './config.js' +import { Decoder } from './decode.js' +import { encodeHeader } from './encode.js' +import { InvalidFrameError, isProtocolError, NotMatchingPingError, UnrequestedPingError } from './errors.js' +import { Flag, FrameType, GoAwayCode } from './frame.js' +import { StreamState, YamuxStream } from './stream.js' +import type { Config } from './config.js' +import type { Frame } from './decode.js' +import type { FrameHeader } from './frame.js' +import type { AbortOptions, MessageStream, MultiaddrConnection, StreamMuxerFactory } from '@libp2p/interface' + +function debugFrame (header: FrameHeader): any { + return { + type: FrameType[header.type], + flags: [ + (header.flag & Flag.SYN) === Flag.SYN ? 'SYN' : undefined, + (header.flag & Flag.ACK) === Flag.ACK ? 'ACK' : undefined, + (header.flag & Flag.FIN) === Flag.FIN ? 'FIN' : undefined, + (header.flag & Flag.RST) === Flag.RST ? 'RST' : undefined + ].filter(Boolean), + streamID: header.streamID, + length: header.length + } +} + +const YAMUX_PROTOCOL_ID = '/yamux/1.0.0' + +export interface YamuxMuxerInit extends Partial { +} + +export class Yamux implements StreamMuxerFactory { + protocol = YAMUX_PROTOCOL_ID + private readonly _init: Partial + + constructor (init: Partial = {}) { + this._init = init + } + + readonly [Symbol.toStringTag] = '@chainsafe/libp2p-yamux' + + readonly [serviceCapabilities]: string[] = [ + '@libp2p/stream-multiplexing' + ] + + createStreamMuxer (maConn: MessageStream): YamuxMuxer { + return new YamuxMuxer(maConn, { + ...this._init + }) + } +} + +export interface CloseOptions extends AbortOptions { + reason?: GoAwayCode +} + +export interface ActivePing extends PromiseWithResolvers { + id: number + start: number +} + +export class YamuxMuxer extends AbstractStreamMuxer { + private readonly config: Config + + /** The next stream id to be used when initiating a new stream */ + private nextStreamID: number + + /** The next ping id to be used when pinging */ + private nextPingID: number + /** Tracking info for the currently active ping */ + private activePing?: ActivePing + /** Round trip time */ + private rtt: number + + /** True if client, false if server */ + private client: boolean + + private localGoAway?: GoAwayCode + private remoteGoAway?: GoAwayCode + + /** Number of tracked inbound streams */ + private numInboundStreams: number + /** Number of tracked outbound streams */ + private numOutboundStreams: number + + private decoder: Decoder + private keepAlive?: RepeatingTask + + constructor (maConn: MessageStream, init: YamuxMuxerInit = {}) { + super(maConn, { + protocol: YAMUX_PROTOCOL_ID, + name: 'yamux' + }) + + this.client = maConn.direction === 'outbound' + this.config = { ...defaultConfig, ...init } + verifyConfig(this.config) + + this.decoder = new Decoder() + + this.numInboundStreams = 0 + this.numOutboundStreams = 0 + + // client uses odd streamIDs, server uses even streamIDs + this.nextStreamID = this.client ? 1 : 2 + + this.nextPingID = 0 + this.rtt = -1 + + this.log.trace('muxer created') + + if (this.config.enableKeepAlive) { + this.log.trace('muxer keepalive enabled interval=%s', this.config.keepAliveInterval) + this.keepAlive = repeatingTask(async (options) => { + try { + await this.ping(options) + } catch (err: any) { + // TODO: should abort here? + this.log.error('ping error: %s', err) + } + }, this.config.keepAliveInterval, { + // send an initial ping to establish RTT + runImmediately: true + }) + this.keepAlive.start() + } + } + + onData (buf: Uint8Array | Uint8ArrayList): void { + for (const frame of this.decoder.emitFrames(buf)) { + this.handleFrame(frame) + } + } + + onCreateStream (): YamuxStream { + if (this.remoteGoAway !== undefined) { + throw new MuxerClosedError('Muxer closed remotely') + } + if (this.localGoAway !== undefined) { + throw new MuxerClosedError('Muxer closed locally') + } + + const id = this.nextStreamID + this.nextStreamID += 2 + + // check against our configured maximum number of outbound streams + if (this.numOutboundStreams >= this.config.maxOutboundStreams) { + throw new TooManyOutboundProtocolStreamsError('max outbound streams exceeded') + } + + this.log.trace('new outgoing stream id=%s', id) + + const stream = this._newStream(id, StreamState.Init, 'outbound') + + this.numOutboundStreams++ + + // send a window update to open the stream on the receiver end. do this in a + // microtask so the stream gets added to the streams array by the superclass + // before we send the SYN flag, otherwise we create a race condition whereby + // we can receive the ACK before the stream is added to the streams list + queueMicrotask(() => { + + stream.sendWindowUpdate() + }) + + return stream + } + + /** + * Initiate a ping and wait for a response + * + * Note: only a single ping will be initiated at a time. + * If a ping is already in progress, a new ping will not be initiated. + * + * @returns the round-trip-time in milliseconds + */ + async ping (options?: AbortOptions): Promise { + if (this.remoteGoAway !== undefined) { + throw new MuxerClosedError('Muxer closed remotely') + } + if (this.localGoAway !== undefined) { + throw new MuxerClosedError('Muxer closed locally') + } + + if (this.activePing != null) { + // an active ping is already in progress, piggyback off that + return raceSignal(this.activePing.promise, options?.signal) + } + + // An active ping does not yet exist, handle the process here + // create active ping + this.activePing = Object.assign(Promise.withResolvers(), { + id: this.nextPingID++, + start: Date.now() + }) + // send ping + this.sendPing(this.activePing.id) + // await pong + try { + this.rtt = await raceSignal(this.activePing.promise, options?.signal) + } finally { + // clean-up active ping + this.activePing = undefined + } + + return this.rtt + } + + /** + * Get the ping round trip time + * + * Note: Will return 0 if no successful ping has yet been completed + * + * @returns the round-trip-time in milliseconds + */ + getRTT (): number { + return this.rtt + } + + /** + * Close the muxer + */ + async close (options: CloseOptions = {}): Promise { + if (this.status !== 'open') { + // already closed + return + } + + try { + const reason = options?.reason ?? GoAwayCode.NormalTermination + + this.log.trace('muxer close reason=%s', GoAwayCode[reason]) + + await super.close(options) + + // send reason to the other side, allow the other side to close gracefully + this.sendGoAway(reason) + } finally { + this.keepAlive?.stop() + } + } + + abort (err: Error): void { + if (this.status !== 'open') { + // already closed + return + } + + try { + super.abort(err) + + let reason = GoAwayCode.InternalError + + if (isProtocolError(err)) { + reason = err.reason + } + + // If reason was provided, use that, otherwise use the presence of `err` to determine the reason + this.log.error('muxer abort reason=%s error=%s', reason, err) + + // send reason to the other side, allow the other side to close gracefully + this.sendGoAway(reason) + } finally { + this.keepAlive?.stop() + } + } + + onTransportClosed (): void { + try { + super.onTransportClosed() + } finally { + this.keepAlive?.stop() + } + } + + /** Create a new stream */ + private _newStream (streamId: number, state: StreamState, direction: 'inbound' | 'outbound'): YamuxStream { + if (this.streams.find(s => s.streamId === streamId) != null) { + throw new InvalidParametersError('Stream already exists with that id') + } + + const stream = new YamuxStream({ + id: `${streamId}`, + streamId, + state, + direction, + sendFrame: this.sendFrame.bind(this), + log: this.log.newScope(`${direction}:${streamId}`), + config: this.config, + getRTT: this.getRTT.bind(this) + }) + + stream.addEventListener('close', () => { + this.closeStream(streamId) + }, { + once: true + }) + + return stream + } + + /** + * closeStream is used to close a stream once both sides have + * issued a close. + */ + private closeStream (id: number): void { + if (this.client === (id % 2 === 0)) { + this.numInboundStreams-- + } else { + this.numOutboundStreams-- + } + } + + private handleFrame (frame: Frame): void { + const { + streamID, + type, + length + } = frame.header + + this.log.trace('received frame %o', debugFrame(frame.header)) + + if (streamID === 0) { + switch (type) { + case FrameType.Ping: + { this.handlePing(frame.header); return } + case FrameType.GoAway: + { this.handleGoAway(length); return } + default: + // Invalid state + throw new InvalidFrameError('Invalid frame type') + } + } else { + switch (frame.header.type) { + case FrameType.Data: + case FrameType.WindowUpdate: + { this.handleStreamMessage(frame); return } + default: + // Invalid state + throw new InvalidFrameError('Invalid frame type') + } + } + } + + private handlePing (header: FrameHeader): void { + // If the ping is initiated by the sender, send a response + if (header.flag === Flag.SYN) { + this.log.trace('received ping request pingId=%s', header.length) + this.sendPing(header.length, Flag.ACK) + } else if (header.flag === Flag.ACK) { + this.log.trace('received ping response pingId=%s', header.length) + this.handlePingResponse(header.length) + } else { + // Invalid state + throw new InvalidFrameError('Invalid frame flag') + } + } + + private handlePingResponse (pingId: number): void { + if (this.activePing === undefined) { + // this ping was not requested + throw new UnrequestedPingError('ping not requested') + } + if (this.activePing.id !== pingId) { + // this ping doesn't match our active ping request + throw new NotMatchingPingError('ping doesn\'t match our id') + } + + // valid ping response + this.activePing.resolve(Date.now() - this.activePing.start) + } + + private handleGoAway (reason: GoAwayCode): void { + this.log.trace('received GoAway reason=%s', GoAwayCode[reason] ?? 'unknown') + this.remoteGoAway = reason + + // reset any streams that are still open and close the muxer + this.abort(new Error('Remote sent GoAway')) + } + + private handleStreamMessage (frame: Frame): void { + const { streamID, flag, type } = frame.header + + if ((flag & Flag.SYN) === Flag.SYN) { + this.incomingStream(streamID) + } + + const stream = this.streams.find(s => s.streamId === streamID) + if (stream === undefined) { + this.log.trace('frame for missing stream id=%s', streamID) + + return + } + + switch (type) { + case FrameType.WindowUpdate: { + stream.handleWindowUpdate(frame); return + } + case FrameType.Data: { + stream.handleData(frame); return + } + default: + throw new Error('unreachable') + } + } + + private incomingStream (id: number): void { + if (this.client !== (id % 2 === 0)) { + throw new InvalidParametersError('Both endpoints are clients') + } + if (this.streams.find(s => s.streamId === id)) { + return + } + + this.log.trace('new incoming stream id=%s', id) + + if (this.localGoAway !== undefined) { + // reject (reset) immediately if we are doing a go away + this.sendFrame({ + type: FrameType.WindowUpdate, + flag: Flag.RST, + streamID: id, + length: 0 + }) + return + } + + // check against our configured maximum number of inbound streams + if (this.numInboundStreams >= this.config.maxInboundStreams) { + this.log('maxIncomingStreams exceeded, forcing stream reset') + this.sendFrame({ + type: FrameType.WindowUpdate, + flag: Flag.RST, + streamID: id, + length: 0 + }); return + } + + // allocate a new stream + const stream = this._newStream(id, StreamState.SYNReceived, 'inbound') + this.onRemoteStream(stream) + + this.numInboundStreams++ + // the stream should now be tracked + } + + private sendFrame (header: FrameHeader, data?: Uint8ArrayList): boolean { + this.log.trace('sending frame %o', debugFrame(header)) + if (header.type === FrameType.Data) { + if (data === undefined) { + throw new InvalidFrameError('Invalid frame') + } + + return this.send(new Uint8ArrayList(encodeHeader(header), data)) + } else { + return this.send(encodeHeader(header)) + } + } + + private sendPing (pingId: number, flag: Flag = Flag.SYN): void { + if (flag === Flag.SYN) { + this.log.trace('sending ping request pingId=%s', pingId) + } else { + this.log.trace('sending ping response pingId=%s', pingId) + } + this.sendFrame({ + type: FrameType.Ping, + flag, + streamID: 0, + length: pingId + }) + } + + private sendGoAway (reason: GoAwayCode = GoAwayCode.NormalTermination): void { + this.log('sending GoAway reason=%s', GoAwayCode[reason]) + this.localGoAway = reason + this.sendFrame({ + type: FrameType.GoAway, + flag: 0, + streamID: 0, + length: reason + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/stream.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/stream.ts new file mode 100644 index 000000000..c6aa07411 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/src/stream.ts @@ -0,0 +1,290 @@ +import { AbstractStream } from '@libp2p/utils' +import { Uint8ArrayList } from 'uint8arraylist' +import { INITIAL_STREAM_WINDOW } from './constants.js' +import { isDataFrame } from './decode.ts' +import { InvalidFrameError, ReceiveWindowExceededError } from './errors.js' +import { Flag, FrameType, HEADER_LENGTH } from './frame.js' +import type { Config } from './config.js' +import type { Frame } from './decode.ts' +import type { FrameHeader } from './frame.js' +import type { AbstractStreamInit, SendResult } from '@libp2p/utils' +import type { AbortOptions } from '@libp2p/interface' + +export enum StreamState { + Init, + SYNSent, + SYNReceived, + Established, + Finished, + Paused +} + +export interface YamuxStreamInit extends AbstractStreamInit { + streamId: number + sendFrame(header: FrameHeader, body?: Uint8ArrayList): boolean + getRTT(): number + config: Config + state: StreamState +} + +/** YamuxStream is used to represent a logical stream within a session */ +export class YamuxStream extends AbstractStream { + streamId: number + state: StreamState + + private readonly config: Config + + /** The number of available bytes to send */ + private sendWindowCapacity: number + /** The number of bytes available to receive in a full window */ + private recvWindow: number + /** The number of available bytes to receive */ + private recvWindowCapacity: number + + /** + * An 'epoch' is the time it takes to process and read data + * + * Used in conjunction with RTT to determine whether to increase the recvWindow + */ + private epochStart: number + private readonly getRTT: () => number + + private readonly sendFrame: (header: FrameHeader, body?: Uint8ArrayList) => boolean + + constructor (init: YamuxStreamInit) { + super(init) + + this.config = init.config + this.streamId = init.streamId + this.state = init.state + this.sendWindowCapacity = INITIAL_STREAM_WINDOW + this.recvWindow = this.config.initialStreamWindowSize + this.recvWindowCapacity = this.recvWindow + this.epochStart = Date.now() + this.getRTT = init.getRTT + this.sendFrame = init.sendFrame + + this.addEventListener('message', () => { + this.sendWindowUpdate() + }) + + this.addEventListener('close', () => { + this.state = StreamState.Finished + }) + } + + /** + * Send a data message to the remote muxer + */ + sendData (buf: Uint8ArrayList): SendResult { + const totalBytes = buf.byteLength + let sentBytes = 0 + let canSendMore = true + + // send in chunks, waiting for window updates + while (buf.byteLength !== 0) { + // we exhausted the send window, sending will resume later + if (this.sendWindowCapacity === 0) { + canSendMore = false + this.log?.trace('sent %d/%d bytes, wait for send window update, status %s', sentBytes, totalBytes, this.status) + break + } + + // send as much as we can + const toSend = Math.min(this.sendWindowCapacity, this.config.maxMessageSize - HEADER_LENGTH, buf.length) + const flags = this.getSendFlags() + + const muxerSendMore = this.sendFrame({ + type: FrameType.Data, + flag: flags, + streamID: this.streamId, + length: toSend + }, buf.sublist(0, toSend)) + + this.sendWindowCapacity -= toSend + + sentBytes += toSend + buf.consume(toSend) + + if (!muxerSendMore) { + canSendMore = muxerSendMore + break + } + } + + return { + sentBytes, + canSendMore + } + } + + /** + * Send a reset message to the remote muxer + */ + async sendReset (): Promise { + this.sendFrame({ + type: FrameType.WindowUpdate, + flag: Flag.RST, + streamID: this.streamId, + length: 0 + }) + } + + /** + * Send a message to the remote muxer, informing them no more data messages + * will be sent by this end of the stream + */ + async sendCloseWrite (): Promise { + const flags = this.getSendFlags() | Flag.FIN + this.sendFrame({ + type: FrameType.WindowUpdate, + flag: flags, + streamID: this.streamId, + length: 0 + }) + } + + /** + * Send a message to the remote muxer, informing them no more data messages + * will be read by this end of the stream - this is a no-op on Yamux streams + */ + async sendCloseRead (options?: AbortOptions): Promise { + options?.signal?.throwIfAborted() + } + + /** + * Stop sending window updates temporarily - in the interim the the remote + * send window will exhaust and the remote will stop sending data + */ + sendPause (): void { + this.state = StreamState.Paused + } + + /** + * Start sending window updates as normal + */ + sendResume (): void { + this.state = StreamState.Established + this.sendWindowUpdate() + } + + /** + * handleWindowUpdate is called when the stream receives a window update frame + */ + handleWindowUpdate (frame: Frame): void { + this.log?.trace('stream received window update') + this.processFlags(frame.header.flag) + + // increase send window + const available = this.sendWindowCapacity + this.sendWindowCapacity += frame.header.length + + // if the update increments a 0 availability, notify the stream that sending can resume + if (available === 0 && frame.header.length > 0) { + this.safeDispatchEvent('drain') + } + } + + /** + * handleData is called when the stream receives a data frame + */ + handleData (frame: Frame): void { + if (!isDataFrame(frame)) { + throw new InvalidFrameError('Frame was not data frame') + } + + this.log?.trace('stream received data') + this.processFlags(frame.header.flag) + + // check that our recv window is not exceeded + if (this.recvWindowCapacity < frame.header.length) { + throw new ReceiveWindowExceededError('Receive window exceeded') + } + + this.recvWindowCapacity -= frame.header.length + + this.onData(frame.data) + } + + /** + * processFlags is used to update the state of the stream based on set flags, if any. + */ + private processFlags (flags: number): void { + if ((flags & Flag.ACK) === Flag.ACK) { + if (this.state === StreamState.SYNSent) { + this.state = StreamState.Established + } + } + + if ((flags & Flag.FIN) === Flag.FIN) { + this.onRemoteCloseWrite() + } + + if ((flags & Flag.RST) === Flag.RST) { + this.onRemoteReset() + } + } + + /** + * getSendFlags determines any flags that are appropriate + * based on the current stream state. + * + * The state is updated as a side-effect. + */ + private getSendFlags (): number { + switch (this.state) { + case StreamState.Init: + this.state = StreamState.SYNSent + return Flag.SYN + case StreamState.SYNReceived: + this.state = StreamState.Established + return Flag.ACK + default: + return 0 + } + } + + /** + * Potentially sends a window update enabling further remote writes to take + * place. + */ + sendWindowUpdate (): void { + // determine the flags if any + const flags = this.getSendFlags() + + // If the stream has already been established + // and we've processed data within the time it takes for 4 round trips + // then we (up to) double the recvWindow + const now = Date.now() + const rtt = this.getRTT() + if (flags === 0 && rtt > -1 && now - this.epochStart < rtt * 4) { + // we've already validated that maxStreamWindowSize can't be more than MAX_UINT32 + this.recvWindow = Math.min(this.recvWindow * 2, this.config.maxStreamWindowSize) + } + + if (this.recvWindowCapacity >= this.recvWindow && flags === 0) { + // a window update isn't needed + return + } + + if (this.state === StreamState.Paused) { + // we don't want any more data from the remote right now + return + } + + // update the receive window + const delta = this.recvWindow - this.recvWindowCapacity + this.recvWindowCapacity = this.recvWindow + + // update the epoch start + this.epochStart = now + + // send window update + this.sendFrame({ + type: FrameType.WindowUpdate, + flag: flags, + streamID: this.streamId, + length: delta + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/typedoc.json new file mode 100644 index 000000000..1c46781ee --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/stream-multiplexer-yamux/typedoc.json @@ -0,0 +1,8 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts", + "./src/config.ts", + "./src/stream.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/.aegir.js b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/.aegir.js new file mode 100644 index 000000000..df0b6684f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/.aegir.js @@ -0,0 +1,10 @@ + +/** @type {import('aegir').PartialOptions} */ +export default { + build: { + config: { + platform: 'node' + }, + bundlesizeMax: '31KB' + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/README.md new file mode 100644 index 000000000..8a23e887b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/README.md @@ -0,0 +1,71 @@ +# @libp2p/tcp + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> A TCP transport for libp2p + +# About + + + +A [libp2p transport](https://docs.libp2p.io/concepts/transports/overview/) based on the TCP networking stack. + +## Example + +```TypeScript +import { createLibp2p } from 'libp2p' +import { tcp } from '@libp2p/tcp' +import { multiaddr } from '@multiformats/multiaddr' + +const node = await createLibp2p({ + transports: [ + tcp() + ] +}) + +const ma = multiaddr('/ip4/123.123.123.123/tcp/1234') + +// dial a TCP connection, timing out after 10 seconds +const connection = await node.dial(ma, { + signal: AbortSignal.timeout(10_000) +}) + +// use connection... +``` + +# Install + +```console +$ npm i @libp2p/tcp +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/transport-tcp/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/transport-tcp/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/package.json new file mode 100644 index 000000000..7a70adb99 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/package.json @@ -0,0 +1,73 @@ +{ + "name": "@libp2p/tcp", + "version": "10.1.18", + "description": "A TCP transport for libp2p", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/transport-tcp#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "keywords": [ + "IPFS", + "TCP", + "libp2p", + "network", + "p2p", + "peer", + "peer-to-peer" + ], + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build", + "test": "aegir test -t node -t electron-main", + "test:chrome": "aegir test -t browser -f ./dist/test/browser.js --cov", + "test:chrome-webworker": "aegir test -t webworker -f ./dist/test/browser.js", + "test:firefox": "aegir test -t browser -f ./dist/test/browser.js -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -f ./dist/test/browser.js -- --browser firefox", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main" + }, + "dependencies": { + "@libp2p/interface": "^2.10.5", + "@libp2p/utils": "^6.7.1", + "@multiformats/multiaddr": "^12.4.4", + "@multiformats/multiaddr-matcher": "^2.0.0", + "@types/sinon": "^17.0.4", + "main-event": "^1.0.1", + "p-event": "^6.0.1", + "progress-events": "^1.0.1", + "race-event": "^1.6.0" + }, + "browser": { + "./dist/src/tcp.js": "./dist/src/tcp.browser.js" + }, + "react-native": { + "./dist/src/tcp.js": "./dist/src/tcp.js" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/constants.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/constants.ts new file mode 100644 index 000000000..ce8820fb1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/constants.ts @@ -0,0 +1,5 @@ +// Time to wait for a connection to close gracefully before destroying it manually +export const CLOSE_TIMEOUT = 500 + +// Close the socket if there is no activity after this long in ms +export const SOCKET_TIMEOUT = 2 * 60_000 // 2 mins diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/index.ts new file mode 100644 index 000000000..94d386e39 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/index.ts @@ -0,0 +1,142 @@ +/** + * @packageDocumentation + * + * A [libp2p transport](https://docs.libp2p.io/concepts/transports/overview/) based on the TCP networking stack. + * + * @example + * + * ```TypeScript + * import { createLibp2p } from 'libp2p' + * import { tcp } from '@libp2p/tcp' + * import { multiaddr } from '@multiformats/multiaddr' + * + * const node = await createLibp2p({ + * transports: [ + * tcp() + * ] + * }) + * + * const ma = multiaddr('/ip4/123.123.123.123/tcp/1234') + * + * // dial a TCP connection, timing out after 10 seconds + * const connection = await node.dial(ma, { + * signal: AbortSignal.timeout(10_000) + * }) + * + * // use connection... + * ``` + */ + +import { TCP } from './tcp.js' +import type { ComponentLogger, CounterGroup, Metrics, CreateListenerOptions, DialTransportOptions, Transport, OutboundConnectionUpgradeEvents } from '@libp2p/interface' +import type { ProgressEvent } from 'progress-events' + +export interface CloseServerOnMaxConnectionsOpts { + /** + * Server listens once connection count is less than `listenBelow` + */ + listenBelow: number + + /** + * Close server once connection count is greater than or equal to `closeAbove` + */ + closeAbove: number + + /** + * Invoked when there was an error listening on a socket + */ + onListenError?(err: Error): void +} + +export interface TCPOptions { + /** + * An optional number in ms that is used as an inactivity timeout after which the socket will be closed + */ + inboundSocketInactivityTimeout?: number + + /** + * An optional number in ms that is used as an inactivity timeout after which the socket will be closed + */ + outboundSocketInactivityTimeout?: number + + /** + * Set this property to reject connections when the server's connection count gets high. + * https://nodejs.org/api/net.html#servermaxconnections + */ + maxConnections?: number + + /** + * Parameter to specify the maximum length of the queue of pending connections + * https://nodejs.org/dist/latest-v18.x/docs/api/net.html#serverlisten + */ + backlog?: number + + /** + * Close server (stop listening for new connections) if connections exceed a limit. + * Open server (start listening for new connections) if connections fall below a limit. + */ + closeServerOnMaxConnections?: CloseServerOnMaxConnectionsOpts + + /** + * Options passed to `net.connect` for every opened TCP socket + */ + dialOpts?: TCPSocketOptions + + /** + * Options passed to every `net.createServer` for every TCP server + */ + listenOpts?: TCPSocketOptions +} + +/** + * Expose a subset of net.connect options + */ +export interface TCPSocketOptions { + /** + * @see https://nodejs.org/api/net.html#socketconnectoptions-connectlistener + */ + noDelay?: boolean + + /** + * @see https://nodejs.org/api/net.html#socketconnectoptions-connectlistener + */ + keepAlive?: boolean + + /** + * @see https://nodejs.org/api/net.html#socketconnectoptions-connectlistener + */ + keepAliveInitialDelay?: number + + /** + * @see https://nodejs.org/api/net.html#new-netsocketoptions + */ + allowHalfOpen?: boolean +} + +export type TCPDialEvents = + OutboundConnectionUpgradeEvents | + ProgressEvent<'tcp:open-connection'> + +export interface TCPDialOptions extends DialTransportOptions, TCPSocketOptions { + +} + +export interface TCPCreateListenerOptions extends CreateListenerOptions, TCPSocketOptions { + +} + +export interface TCPComponents { + metrics?: Metrics + logger: ComponentLogger +} + +export interface TCPMetrics { + events: CounterGroup<'error' | 'timeout' | 'connect' | 'abort'> + errors: CounterGroup<'outbound_to_connection' | 'outbound_upgrade'> +} + +export function tcp (init: TCPOptions = {}): (components: TCPComponents) => Transport { + return (components: TCPComponents) => { + return new TCP(components, init) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/listener.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/listener.ts new file mode 100644 index 000000000..121053ff7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/listener.ts @@ -0,0 +1,347 @@ +import net from 'net' +import { AlreadyStartedError, InvalidParametersError, NotStartedError } from '@libp2p/interface' +import { getThinWaistAddresses } from '@libp2p/utils' +import { multiaddr } from '@multiformats/multiaddr' +import { TypedEventEmitter, setMaxListeners } from 'main-event' +import { pEvent } from 'p-event' +import { toMultiaddrConnection } from './socket-to-conn.js' +import { multiaddrToNetConfig } from './utils.js' +import type { CloseServerOnMaxConnectionsOpts, TCPCreateListenerOptions } from './index.js' +import type { NetConfig } from './utils.js' +import type { ComponentLogger, Logger, MultiaddrConnection, CounterGroup, MetricGroup, Metrics, Listener, ListenerEvents, Upgrader } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +interface Context extends TCPCreateListenerOptions { + upgrader: Upgrader + inactivityTimeout?: number + maxConnections?: number + backlog?: number + metrics?: Metrics + closeServerOnMaxConnections?: CloseServerOnMaxConnectionsOpts + logger: ComponentLogger +} + +interface TCPListenerMetrics { + status?: MetricGroup + errors?: CounterGroup + events?: CounterGroup +} + +enum TCPListenerStatusCode { + /** + * When server object is initialized but we don't know the listening address + * yet or the server object is stopped manually, can be resumed only by + * calling listen() + */ + INACTIVE = 0, + ACTIVE = 1, + /* During the connection limits */ + PAUSED = 2 +} + +type Status = { code: TCPListenerStatusCode.INACTIVE } | { + code: Exclude + listeningAddr: Multiaddr + netConfig: NetConfig +} + +export class TCPListener extends TypedEventEmitter implements Listener { + private readonly server: net.Server + /** Keep track of open sockets to destroy in case of timeout */ + private readonly sockets = new Set() + private status: Status = { code: TCPListenerStatusCode.INACTIVE } + private metrics: TCPListenerMetrics + private addr: string + private readonly log: Logger + private readonly shutdownController: AbortController + + constructor (private readonly context: Context) { + super() + + context.keepAlive = context.keepAlive ?? true + context.noDelay = context.noDelay ?? true + + this.shutdownController = new AbortController() + setMaxListeners(Infinity, this.shutdownController.signal) + + this.log = context.logger.forComponent('libp2p:tcp:listener') + this.addr = 'unknown' + this.server = net.createServer(context, this.onSocket.bind(this)) + + // https://nodejs.org/api/net.html#servermaxconnections + // If set reject connections when the server's connection count gets high + // Useful to prevent too resource exhaustion via many open connections on + // high bursts of activity + if (context.maxConnections !== undefined) { + this.server.maxConnections = context.maxConnections + } + + if (context.closeServerOnMaxConnections != null) { + // Sanity check options + if (context.closeServerOnMaxConnections.closeAbove < context.closeServerOnMaxConnections.listenBelow) { + throw new InvalidParametersError('closeAbove must be >= listenBelow') + } + } + + context.metrics?.registerMetricGroup('libp2p_tcp_inbound_connections_total', { + label: 'address', + help: 'Current active connections in TCP listener', + calculate: () => { + return { + [this.addr]: this.sockets.size + } + } + }) + + this.metrics = { + status: context.metrics?.registerMetricGroup('libp2p_tcp_listener_status_info', { + label: 'address', + help: 'Current status of the TCP listener socket' + }), + errors: context.metrics?.registerMetricGroup('libp2p_tcp_listener_errors_total', { + label: 'address', + help: 'Total count of TCP listener errors by type' + }), + events: context.metrics?.registerMetricGroup('libp2p_tcp_listener_events_total', { + label: 'address', + help: 'Total count of TCP listener events by type' + }) + } + + this.server + .on('listening', () => { + // we are listening, register metrics for our port + const address = this.server.address() + + if (address == null) { + this.addr = 'unknown' + } else if (typeof address === 'string') { + // unix socket + this.addr = address + } else { + this.addr = `${address.address}:${address.port}` + } + + this.metrics.status?.update({ + [this.addr]: TCPListenerStatusCode.ACTIVE + }) + + this.safeDispatchEvent('listening') + }) + .on('error', err => { + this.metrics.errors?.increment({ [`${this.addr} listen_error`]: true }) + this.safeDispatchEvent('error', { detail: err }) + }) + .on('close', () => { + this.metrics.status?.update({ + [this.addr]: this.status.code + }) + + // If this event is emitted, the transport manager will remove the + // listener from it's cache in the meanwhile if the connections are + // dropped then listener will start listening again and the transport + // manager will not be able to close the server + if (this.status.code !== TCPListenerStatusCode.PAUSED) { + this.safeDispatchEvent('close') + } + }) + .on('drop', () => { + this.metrics.events?.increment({ [`${this.addr} drop`]: true }) + }) + } + + private onSocket (socket: net.Socket): void { + this.metrics.events?.increment({ [`${this.addr} connection`]: true }) + + if (this.status.code !== TCPListenerStatusCode.ACTIVE) { + socket.destroy() + throw new NotStartedError('Server is not listening yet') + } + + let maConn: MultiaddrConnection + try { + maConn = toMultiaddrConnection({ + socket, + inactivityTimeout: this.context.inactivityTimeout, + metrics: this.metrics?.events, + metricPrefix: `${this.addr} `, + direction: 'inbound', + localAddr: this.status.listeningAddr, + log: this.context.logger.forComponent('libp2p:tcp:connection:inbound') + }) + } catch (err: any) { + this.log.error('inbound connection failed', err) + this.metrics.errors?.increment({ [`${this.addr} inbound_to_connection`]: true }) + socket.destroy() + return + } + + this.log('new inbound connection %s', maConn.remoteAddr) + this.sockets.add(socket) + + this.context.upgrader.upgradeInbound(maConn, { + signal: this.shutdownController.signal + }) + .then(() => { + this.log('inbound connection upgraded %s', maConn.remoteAddr) + + socket.once('close', () => { + this.sockets.delete(socket) + + if ( + this.context.closeServerOnMaxConnections != null && + this.sockets.size < this.context.closeServerOnMaxConnections.listenBelow + ) { + // The most likely case of error is if the port taken by this + // application is bound by another process during the time the + // server if closed. In that case there's not much we can do. + // resume() will be called again every time a connection is + // dropped, which acts as an eventual retry mechanism. + // onListenError allows the consumer act on this. + this.resume().catch(e => { + this.log.error('error attempting to listen server once connection count under limit', e) + this.context.closeServerOnMaxConnections?.onListenError?.(e as Error) + }) + } + }) + + if ( + this.context.closeServerOnMaxConnections != null && + this.sockets.size >= this.context.closeServerOnMaxConnections.closeAbove + ) { + this.pause() + } + }) + .catch(async err => { + this.log.error('inbound connection upgrade failed', err) + this.metrics.errors?.increment({ [`${this.addr} inbound_upgrade`]: true }) + this.sockets.delete(socket) + maConn.abort(err) + }) + } + + getAddrs (): Multiaddr[] { + if (this.status.code === TCPListenerStatusCode.INACTIVE) { + return [] + } + + const address = this.server.address() + + if (address == null) { + return [] + } + + if (typeof address === 'string') { + return [ + multiaddr(`/unix/${encodeURIComponent(address)}`) + ] + } + + return getThinWaistAddresses(this.status.listeningAddr, address.port) + } + + updateAnnounceAddrs (): void { + + } + + async listen (ma: Multiaddr): Promise { + if (this.status.code === TCPListenerStatusCode.ACTIVE || this.status.code === TCPListenerStatusCode.PAUSED) { + throw new AlreadyStartedError('server is already listening') + } + + try { + this.status = { + code: TCPListenerStatusCode.ACTIVE, + listeningAddr: ma, + netConfig: multiaddrToNetConfig(ma, this.context) + } + + await this.resume() + } catch (err) { + this.status = { code: TCPListenerStatusCode.INACTIVE } + throw err + } + } + + async close (): Promise { + const events: Array> = [] + + if (this.server.listening) { + events.push(pEvent(this.server, 'close')) + } + + // shut down the server socket, permanently + this.pause(true) + + // stop any in-progress connection upgrades + this.shutdownController.abort() + + // synchronously close any open connections - should be done after closing + // the server socket in case new sockets are opened during the shutdown + this.sockets.forEach(socket => { + if (socket.readable) { + events.push(pEvent(socket, 'close')) + socket.destroy() + } + }) + + await Promise.all(events) + } + + /** + * Can resume a stopped or start an inert server + */ + private async resume (): Promise { + if (this.server.listening || this.status.code === TCPListenerStatusCode.INACTIVE) { + return + } + + const netConfig = this.status.netConfig + + await new Promise((resolve, reject) => { + // NOTE: 'listening' event is only fired on success. Any error such as + // port already bound, is emitted via 'error' + this.server.once('error', reject) + this.server.listen(netConfig, resolve) + }) + + this.status = { ...this.status, code: TCPListenerStatusCode.ACTIVE } + this.log('listening on %s', this.server.address()) + } + + private pause (permanent: boolean = false): void { + if (!this.server.listening && this.status.code === TCPListenerStatusCode.PAUSED && permanent) { + this.status = { code: TCPListenerStatusCode.INACTIVE } + return + } + + if (!this.server.listening || this.status.code !== TCPListenerStatusCode.ACTIVE) { + return + } + + this.log('closing server on %s', this.server.address()) + + // NodeJS implementation tracks listening status with `this._handle` property. + // - Server.close() sets this._handle to null immediately. If this._handle is null, NotStartedError is thrown + // - Server.listening returns `this._handle !== null` https://github.com/nodejs/node/blob/386d761943bb1b217fba27d6b80b658c23009e60/lib/net.js#L1675 + // - Server.listen() if `this._handle !== null` throws AlreadyStartedError + // + // NOTE: Both listen and close are technically not async actions, so it's not necessary to track + // states 'pending-close' or 'pending-listen' + + // From docs https://nodejs.org/api/net.html#serverclosecallback + // Stops the server from accepting new connections and keeps existing connections. + // 'close' event is emitted only emitted when all connections are ended. + // The optional callback will be called once the 'close' event occurs. + + // We need to set this status before closing server, so other procedures are aware + // during the time the server is closing + this.status = permanent ? { code: TCPListenerStatusCode.INACTIVE } : { ...this.status, code: TCPListenerStatusCode.PAUSED } + + // stop accepting incoming connections - existing connections are maintained + // - any callback passed here would be invoked after existing connections + // close, we want to maintain them so no callback is passed otherwise his + // method will never return + this.server.close() + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/socket-to-conn.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/socket-to-conn.ts new file mode 100644 index 000000000..089ed5cde --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/socket-to-conn.ts @@ -0,0 +1,139 @@ +import { InvalidParametersError, TimeoutError } from '@libp2p/interface' +import { AbstractMultiaddrConnection, socketWriter, ipPortToMultiaddr } from '@libp2p/utils' +import { Unix } from '@multiformats/multiaddr-matcher' +import { raceEvent } from 'race-event' +import type { AbortOptions, MultiaddrConnection } from '@libp2p/interface' +import type { AbstractMultiaddrConnectionInit, SendResult, SocketWriter } from '@libp2p/utils' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Socket } from 'net' +import type { Uint8ArrayList } from 'uint8arraylist' + +export interface TCPSocketMultiaddrConnectionInit extends Omit { + socket: Socket + remoteAddr?: Multiaddr +} + +class TCPSocketMultiaddrConnection extends AbstractMultiaddrConnection { + private socket: Socket + private writer: SocketWriter + + constructor (init: TCPSocketMultiaddrConnectionInit) { + let remoteAddr = init.remoteAddr + + // check if we are connected on a unix path + if (init.localAddr != null && Unix.matches(init.localAddr)) { + remoteAddr = init.localAddr + } else if (remoteAddr == null) { + if (init.socket.remoteAddress == null || init.socket.remotePort == null) { + // this can be undefined if the socket is destroyed (for example, if the client disconnected) + // https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketremoteaddress + throw new InvalidParametersError('Could not determine remote address or port') + } + + remoteAddr = ipPortToMultiaddr(init.socket.remoteAddress, init.socket.remotePort) + } + + super({ + ...init, + remoteAddr + }) + + this.socket = init.socket + + // handle incoming data + this.socket.on('data', buf => { + this.onData(buf) + }) + + // handle socket errors + this.socket.on('error', err => { + this.abort(err) + }) + + // by default there is no timeout + // https://nodejs.org/dist/latest-v16.x/docs/api/net.html#socketsettimeouttimeout-callback + this.socket.setTimeout(init.inactivityTimeout ?? (2 * 60 * 1_000)) + + this.socket.once('timeout', () => { + // if the socket times out due to inactivity we must manually close the connection + // https://nodejs.org/dist/latest-v16.x/docs/api/net.html#event-timeout + this.abort(new TimeoutError()) + }) + + this.socket.once('end', () => { + // the remote sent a FIN packet which means no more data will be sent + // https://nodejs.org/dist/latest-v16.x/docs/api/net.html#event-end + this.onRemoteCloseWrite() + }) + + this.socket.once('close', hadError => { + if (hadError) { + this.abort(new Error('TCP transmission error')) + return + } + + this.onRemoteCloseWrite() + this.onClosed() + }) + + // the socket can accept more data + this.socket.on('drain', () => { + this.safeDispatchEvent('drain') + }) + + this.writer = socketWriter(this.socket) + } + + sendData (data: Uint8ArrayList): SendResult { + let sentBytes = 0 + let canSendMore = true + + for (const buf of data) { + sentBytes += buf.byteLength + canSendMore = this.writer.write(buf) + + if (!canSendMore) { + break + } + } + + return { + sentBytes, + canSendMore + } + } + + async sendCloseWrite (options?: AbortOptions): Promise { + if (this.socket.destroyed) { + return + } + + this.socket.end() + + await raceEvent(this.socket, 'close', options?.signal) + } + + async sendCloseRead (options?: AbortOptions): Promise { + options?.signal?.throwIfAborted() + } + + sendReset (): void { + this.socket.resetAndDestroy() + } + + sendPause (): void { + this.socket.pause() + } + + sendResume (): void { + this.socket.resume() + } +} + +/** + * Convert a socket into a MultiaddrConnection + * https://github.com/libp2p/interface-transport#multiaddrconnection + */ +export const toMultiaddrConnection = (init: TCPSocketMultiaddrConnectionInit): MultiaddrConnection => { + return new TCPSocketMultiaddrConnection(init) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/tcp.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/tcp.browser.ts new file mode 100644 index 000000000..93610a383 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/tcp.browser.ts @@ -0,0 +1,34 @@ +import { serviceCapabilities, transportSymbol } from '@libp2p/interface' +import type { TCPDialEvents } from './index.js' +import type { Connection, Transport, Listener } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +export class TCP implements Transport { + constructor () { + throw new Error('TCP connections are not possible in browsers') + } + + readonly [transportSymbol] = true + + readonly [Symbol.toStringTag] = '@libp2p/tcp' + + readonly [serviceCapabilities]: string[] = [ + '@libp2p/transport' + ] + + async dial (): Promise { + throw new Error('TCP connections are not possible in browsers') + } + + createListener (): Listener { + throw new Error('TCP connections are not possible in browsers') + } + + listenFilter (): Multiaddr[] { + return [] + } + + dialFilter (): Multiaddr[] { + return [] + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/tcp.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/tcp.ts new file mode 100644 index 000000000..51e08cec3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/tcp.ts @@ -0,0 +1,214 @@ +/** + * @packageDocumentation + * + * A [libp2p transport](https://docs.libp2p.io/concepts/transports/overview/) based on the TCP networking stack. + * + * @example + * + * ```TypeScript + * import { createLibp2p } from 'libp2p' + * import { tcp } from '@libp2p/tcp' + * import { multiaddr } from '@multiformats/multiaddr' + * + * const node = await createLibp2p({ + * transports: [ + * tcp() + * ] + * }) + * + * const ma = multiaddr('/ip4/123.123.123.123/tcp/1234') + * + * // dial a TCP connection, timing out after 10 seconds + * const connection = await node.dial(ma, { + * signal: AbortSignal.timeout(10_000) + * }) + * + * // use connection... + * ``` + */ + +import net from 'net' +import { AbortError, TimeoutError, serviceCapabilities, transportSymbol } from '@libp2p/interface' +import { TCP as TCPMatcher } from '@multiformats/multiaddr-matcher' +import { CustomProgressEvent } from 'progress-events' +import { TCPListener } from './listener.js' +import { toMultiaddrConnection } from './socket-to-conn.js' +import { multiaddrToNetConfig } from './utils.js' +import type { TCPComponents, TCPCreateListenerOptions, TCPDialEvents, TCPDialOptions, TCPMetrics, TCPOptions } from './index.js' +import type { Logger, Connection, Transport, Listener, MultiaddrConnection } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Socket, IpcSocketConnectOpts, TcpSocketConnectOpts } from 'net' + +export class TCP implements Transport { + private readonly opts: TCPOptions + private readonly metrics?: TCPMetrics + private readonly components: TCPComponents + private readonly log: Logger + + constructor (components: TCPComponents, options: TCPOptions = {}) { + this.log = components.logger.forComponent('libp2p:tcp') + this.opts = options + this.components = components + + if (components.metrics != null) { + this.metrics = { + events: components.metrics.registerCounterGroup('libp2p_tcp_dialer_events_total', { + label: 'event', + help: 'Total count of TCP dialer events by type' + }), + errors: components.metrics.registerCounterGroup('libp2p_tcp_dialer_errors_total', { + label: 'event', + help: 'Total count of TCP dialer events by type' + }) + } + } + } + + readonly [transportSymbol] = true + + readonly [Symbol.toStringTag] = '@libp2p/tcp' + + readonly [serviceCapabilities]: string[] = [ + '@libp2p/transport' + ] + + async dial (ma: Multiaddr, options: TCPDialOptions): Promise { + options.keepAlive = options.keepAlive ?? true + options.noDelay = options.noDelay ?? true + + // options.signal destroys the socket before 'connect' event + const socket = await this._connect(ma, options) + + let maConn: MultiaddrConnection + + try { + maConn = toMultiaddrConnection({ + socket, + inactivityTimeout: this.opts.outboundSocketInactivityTimeout, + metrics: this.metrics?.events, + direction: 'outbound', + remoteAddr: ma, + log: this.components.logger.forComponent('libp2p:tcp:connection:outbound') + }) + } catch (err: any) { + this.metrics?.errors.increment({ outbound_to_connection: true }) + socket.destroy(err) + throw err + } + + try { + this.log('new outbound connection %s', maConn.remoteAddr) + return await options.upgrader.upgradeOutbound(maConn, options) + } catch (err: any) { + this.metrics?.errors.increment({ outbound_upgrade: true }) + this.log.error('error upgrading outbound connection', err) + maConn.abort(err) + throw err + } + } + + async _connect (ma: Multiaddr, options: TCPDialOptions): Promise { + options.signal.throwIfAborted() + options.onProgress?.(new CustomProgressEvent('tcp:open-connection')) + + let rawSocket: Socket + + return new Promise((resolve, reject) => { + const start = Date.now() + const cOpts = multiaddrToNetConfig(ma, { + ...(this.opts.dialOpts ?? {}), + ...options + }) as (IpcSocketConnectOpts & TcpSocketConnectOpts) + + this.log('dialing %a', ma) + rawSocket = net.connect(cOpts) + + const onError = (err: Error): void => { + this.log.error('dial to %a errored - %e', ma, err) + const cOptsStr = cOpts.path ?? `${cOpts.host ?? ''}:${cOpts.port}` + err.message = `connection error ${cOptsStr}: ${err.message}` + this.metrics?.events.increment({ error: true }) + done(err) + } + + const onTimeout = (): void => { + this.log('connection timeout %a', ma) + this.metrics?.events.increment({ timeout: true }) + + const err = new TimeoutError(`Connection timeout after ${Date.now() - start}ms`) + // Note: this will result in onError() being called + rawSocket.emit('error', err) + } + + const onConnect = (): void => { + this.log('connection opened %a', ma) + this.metrics?.events.increment({ connect: true }) + done() + } + + const onAbort = (): void => { + this.log('connection aborted %a', ma) + this.metrics?.events.increment({ abort: true }) + done(new AbortError()) + } + + const done = (err?: Error): void => { + rawSocket.removeListener('error', onError) + rawSocket.removeListener('timeout', onTimeout) + rawSocket.removeListener('connect', onConnect) + + if (options.signal != null) { + options.signal.removeEventListener('abort', onAbort) + } + + if (err != null) { + reject(err); return + } + + resolve(rawSocket) + } + + rawSocket.on('error', onError) + rawSocket.on('timeout', onTimeout) + rawSocket.on('connect', onConnect) + + options.signal.addEventListener('abort', onAbort) + }) + .catch(err => { + rawSocket?.destroy() + throw err + }) + } + + /** + * Creates a TCP listener. The provided `handler` function will be called + * anytime a new incoming Connection has been successfully upgraded via + * `upgrader.upgradeInbound`. + */ + createListener (options: TCPCreateListenerOptions): Listener { + return new TCPListener({ + ...(this.opts.listenOpts ?? {}), + ...options, + maxConnections: this.opts.maxConnections, + backlog: this.opts.backlog, + closeServerOnMaxConnections: this.opts.closeServerOnMaxConnections, + inactivityTimeout: this.opts.inboundSocketInactivityTimeout, + metrics: this.components.metrics, + logger: this.components.logger + }) + } + + /** + * Takes a list of `Multiaddr`s and returns only valid TCP addresses + */ + listenFilter (multiaddrs: Multiaddr[]): Multiaddr[] { + return multiaddrs.filter(ma => TCPMatcher.exactMatch(ma) || ma.toString().startsWith('/unix/')) + } + + /** + * Filter check for all Multiaddrs that this transport can dial + */ + dialFilter (multiaddrs: Multiaddr[]): Multiaddr[] { + return this.listenFilter(multiaddrs) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/utils.ts new file mode 100644 index 000000000..797b62f17 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/src/utils.ts @@ -0,0 +1,29 @@ +import os from 'os' +import path from 'path' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { ListenOptions, IpcSocketConnectOpts, TcpSocketConnectOpts } from 'net' + +export type NetConfig = ListenOptions | (IpcSocketConnectOpts & TcpSocketConnectOpts) + +export function multiaddrToNetConfig (addr: Multiaddr, config: NetConfig = {}): NetConfig { + const listenPath = addr.getPath() + + // unix socket listening + if (listenPath != null) { + if (os.platform() === 'win32') { + // Use named pipes on Windows systems. + return { path: path.join('\\\\.\\pipe\\', listenPath) } + } else { + return { path: listenPath } + } + } + + const options = addr.toOptions() + + // tcp listening + return { + ...config, + ...options, + ipv6Only: options.family === 6 + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/typedoc.json new file mode 100644 index 000000000..db0b0747e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/transport-tcp/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/README.md b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/README.md new file mode 100644 index 000000000..2d88947e7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/README.md @@ -0,0 +1,71 @@ +# @libp2p/utils + +[![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) +[![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p/main.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p/actions/workflows/main.yml?query=branch%3Amain) + +> Package to aggregate shared logic and dependencies for the libp2p ecosystem + +# About + + + +The libp2p ecosystem has lots of repos with it comes several problems like: + +- Domain logic dedupe - all modules shared a lot of logic like validation, streams handling, etc. +- Dependencies management - it's really easy with so many repos for dependencies to go out of control, they become outdated, different repos use different modules to do the same thing (like merging defaults options), browser bundles ends up with multiple versions of the same package, bumping versions is cumbersome to do because we need to go through several repos, etc. + +These problems are the motivation for this package, having shared logic in this package avoids creating cyclic dependencies, centralizes common use modules/functions (exactly like aegir does for the tooling), semantic versioning for 3rd party dependencies is handled in one single place (a good example is going from streams 2 to 3) and maintainers should only care about having `libp2p-utils` updated. + +## Example + +Each function should be imported directly. + +```TypeScript +import { ipPortToMultiaddr } from '@libp2p/utils' + +const ma = ipPortToMultiaddr('127.0.0.1', 9000) +``` + +# Install + +```console +$ npm i @libp2p/utils +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p/blob/main/packages/utils/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p/blob/main/packages/utils/LICENSE-MIT) / ) + +# Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/package.json new file mode 100644 index 000000000..1e75ecc65 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/package.json @@ -0,0 +1,82 @@ +{ + "name": "@libp2p/utils", + "version": "6.7.1", + "description": "Package to aggregate shared logic and dependencies for the libp2p ecosystem", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/utils#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "type": "module", + "types": "./dist/src/index.d.ts", + "files": [ + "src", + "dist", + "!dist/test", + "!**/*.tsbuildinfo" + ], + "exports": { + ".": { + "types": "./dist/src/index.d.ts", + "import": "./dist/src/index.js" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "doc-check": "aegir doc-check", + "build": "aegir build", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:chrome-webworker": "aegir test -t webworker", + "test:firefox": "aegir test -t browser -- --browser firefox", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main" + }, + "dependencies": { + "@types/netmask": "^2.0.5", + "@chainsafe/is-ip": "^2.1.0", + "@chainsafe/netmask": "^2.0.0", + "@libp2p/crypto": "^5.1.7", + "@libp2p/interface": "^2.10.5", + "@libp2p/logger": "^5.1.21", + "@multiformats/multiaddr": "^12.4.4", + "@sindresorhus/fnv1a": "^3.1.0", + "any-signal": "^4.1.1", + "delay": "^6.0.0", + "is-loopback-addr": "^2.0.2", + "is-plain-obj": "^4.1.0", + "it-length-prefixed": "^10.0.1", + "it-pipe": "^3.0.1", + "it-pushable": "^3.2.3", + "it-stream-types": "^2.0.2", + "main-event": "^1.0.1", + "netmask": "^2.0.2", + "p-defer": "^4.0.1", + "p-event": "^6.0.1", + "race-event": "^1.6.0", + "race-signal": "^1.1.3", + "uint8-varint": "^2.0.4", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + }, + "browser": { + "./dist/src/get-thin-waist-addresses.js": "./dist/src/get-thin-waist-addresses.browser.js", + "./dist/src/socket-writer.js": "./dist/src/socket-writer.browser.js" + }, + "react-native": { + "./dist/src/get-thin-waist-addresses.js": "./dist/src/get-thin-waist-addresses.js", + "./dist/src/socket-writer.js": "./dist/src/socket-writer.js" + }, + "sideEffects": false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-message-stream.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-message-stream.ts new file mode 100644 index 000000000..775e4a7d6 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-message-stream.ts @@ -0,0 +1,508 @@ +import { StreamResetError, StreamStateError, TypedEventEmitter, StreamMessageEvent, StreamBufferError, StreamResetEvent, StreamAbortEvent, StreamCloseEvent } from '@libp2p/interface' +import { raceEvent } from 'race-event' +import { Uint8ArrayList } from 'uint8arraylist' +import type { MessageStreamEvents, MessageStreamStatus, MessageStream, AbortOptions, MessageStreamTimeline, MessageStreamReadStatus, MessageStreamWriteStatus, MessageStreamDirection } from '@libp2p/interface' +import type { Logger } from '@libp2p/logger' +import { pushable } from 'it-pushable' + +const DEFAULT_MAX_PAUSE_BUFFER_LENGTH = Math.pow(2, 20) * 4 // 4MB + +export interface MessageStreamInit { + /** + * A Logger implementation used to log stream-specific information + */ + log: Logger + + /** + * If no data is sent or received in this number of ms the stream will be + * reset and an 'error' event emitted. + * + * @default 120_000 + */ + inactivityTimeout?: number + + /** + * The maximum number of bytes to store when paused. If receipt of more bytes + * from the remote end of the stream causes the buffer size to exceed this + * value the stream will be reset and an 'error' event emitted. + */ + maxPauseBufferLength?: number + + /** + * The stream direction + */ + direction?: MessageStreamDirection +} + +export interface SendResult { + /** + * The number of bytes from the passed buffer that were sent + */ + sentBytes: number + + /** + * If the underlying resource can accept more data immediately. If `true`, + * `sent` must equal the `.byteLength` of the buffer passed to `sendData`. + */ + canSendMore: boolean +} + +export abstract class AbstractMessageStream extends TypedEventEmitter implements MessageStream { + public readonly timeline: MessageStreamTimeline + public status: MessageStreamStatus + public readStatus: MessageStreamReadStatus + public writeStatus: MessageStreamWriteStatus + public remoteReadStatus: MessageStreamReadStatus + public remoteWriteStatus: MessageStreamWriteStatus + public inactivityTimeout: number + public maxPauseBufferLength: number + public readonly log: Logger + public direction: MessageStreamDirection + + protected readonly pauseBuffer: Uint8ArrayList + protected readonly sendQueue: Uint8ArrayList + + constructor (init: MessageStreamInit) { + super() + + this.log = init.log + this.direction = init.direction ?? 'outbound' + this.status = 'open' + this.readStatus = 'readable' + this.remoteReadStatus = 'readable' + this.writeStatus = 'writable' + this.remoteWriteStatus = 'writable' + this.inactivityTimeout = init.inactivityTimeout ?? 120_000 + this.maxPauseBufferLength = init.maxPauseBufferLength ?? DEFAULT_MAX_PAUSE_BUFFER_LENGTH + this.pauseBuffer = new Uint8ArrayList() + this.sendQueue = new Uint8ArrayList() + this.timeline = { + open: Date.now() + } + + this.processSendQueue = this.processSendQueue.bind(this) + + this.addEventListener('drain', () => { + this.log('begin sending again, write status was %s, send queue size', this.writeStatus, this.sendQueue.byteLength) + + if (this.writeStatus === 'paused') { + this.writeStatus = 'writable' + } + + this.processSendQueue() + }) + } + + async * [Symbol.asyncIterator] (): AsyncGenerator { + const output = pushable() + + const onMessage = (evt: StreamMessageEvent): void => { + output.push(evt.data) + } + this.addEventListener('message', onMessage) + + const onClose = (evt: StreamCloseEvent): void => { + output.end(evt.error) + } + this.addEventListener('close', onClose) + + const onRemoteCloseWrite = (): void => { + output.end() + } + this.addEventListener('remoteCloseWrite', onRemoteCloseWrite) + + try { + yield * output + } finally { + this.removeEventListener('message', onMessage) + this.removeEventListener('close', onClose) + this.removeEventListener('remoteCloseWrite', onRemoteCloseWrite) + } + } + + send (data: Uint8Array | Uint8ArrayList): boolean { + if (this.writeStatus !== 'writable' && this.writeStatus !== 'paused') { + // return true to make this a no-op otherwise callers might wait for a + // "drain" event that will never come + return true + } + + this.sendQueue.append(data) + return this.processSendQueue() + } + + /** + * Close immediately for reading and writing and send a reset message (local + * error) + */ + abort (err: Error): void { + if (this.status === 'closed' || this.status === 'aborted' || this.status === 'reset') { + return + } + + this.log.error('abort with error - %e', err) + + try { + this.sendReset(err) + } catch (err: any) { + this.log('failed to send reset to remote - %e', err) + } + + this.status = 'aborted' + this.writeStatus = 'closed' + this.remoteWriteStatus = 'closed' + this.readStatus = 'closed' + this.remoteReadStatus = 'closed' + + this.timeline.abort = Date.now() + this.timeline.closeWrite = Date.now() + this.timeline.remoteCloseWrite = Date.now() + this.timeline.closeRead = Date.now() + this.timeline.remoteCloseRead = Date.now() + + if (this.pauseBuffer.byteLength > 0) { + this.pauseBuffer.consume(this.pauseBuffer.byteLength) + } + + if (this.sendQueue.byteLength > 0) { + this.sendQueue.consume(this.sendQueue.byteLength) + } + + this.dispatchEvent(new StreamAbortEvent(err)) + } + + async close (options?: AbortOptions): Promise { + if (this.status !== 'open') { + return + } + + this.log.trace('closing gracefully') + + this.status = 'closing' + + await Promise.all([ + this.closeRead(options), + this.closeWrite(options) + ]) + + this.log.trace('closed gracefully') + + this.onClosed() + } + + async closeWrite (options?: AbortOptions): Promise { + if (this.writeStatus === 'closing' || this.writeStatus === 'closed') { + return + } + + const startingWriteStatus = this.writeStatus + + this.writeStatus = 'closing' + + if (startingWriteStatus === 'paused') { + this.log.trace('waiting for drain before closing writable end of stream, %d unsent bytes', this.sendQueue.byteLength) + await raceEvent(this, 'drain', options?.signal) + } + + await this.sendCloseWrite(options) + + this.writeStatus = 'closed' + this.timeline.closeWrite = Date.now() + + this.log('closed writable end gracefully') + + setTimeout(() => { + this.safeDispatchEvent('closeWrite') + + if (this.remoteWriteStatus === 'closed') { + this.onClosed() + } + }, 0) + } + + async closeRead (options?: AbortOptions): Promise { + if (this.readStatus === 'closing' || this.readStatus === 'closed') { + return + } + + this.readStatus = 'closing' + + await this.sendCloseRead(options) + + this.readStatus = 'closed' + this.timeline.closeRead = Date.now() + + this.log('closed readable end gracefully') + + setTimeout(() => { + this.safeDispatchEvent('closeRead') + }, 0) + } + + pause (): void { + this.log.trace('pausing readable end') + + if (this.readStatus !== 'readable') { + return + } + + this.readStatus = 'paused' + this.sendPause() + } + + resume (): void { + this.log.trace('resuming readable end') + + if (this.readStatus !== 'paused') { + return + } + + this.readStatus = 'readable' + + // emit any data that accumulated while we were paused + if (this.pauseBuffer.byteLength > 0) { + const data = new Uint8ArrayList(this.pauseBuffer) + this.pauseBuffer.consume(this.pauseBuffer.byteLength) + this.dispatchEvent(new StreamMessageEvent(data)) + } + + if (this.writeStatus === 'closing' || this.writeStatus === 'closed' + || this.remoteReadStatus === 'closing' || this.remoteReadStatus === 'closed' + ) { + return + } + + this.sendResume() + } + + push (data: Uint8Array | Uint8ArrayList): void { + if (data.byteLength === 0) { + return + } + + this.pauseBuffer.append(data) + + setTimeout(() => { + this.dispatchPauseBuffer() + }, 0) + } + + /** + * When an extending class reads data from it's implementation-specific source, + * call this method to allow the stream consumer to read the data. + */ + onData (data: Uint8Array | Uint8ArrayList): void { + // discard the data if our readable end is closed + if (this.readStatus === 'closing' || this.readStatus === 'closed') { + return + } + + // check the pause buffer in case data has been pushed onto the stream + this.dispatchPauseBuffer() + + if (data.byteLength === 0) { + return + } + + if (this.readStatus === 'readable') { + this.dispatchEvent(new StreamMessageEvent(data)) + } else if (this.readStatus === 'paused') { + // queue the message + this.pauseBuffer.append(data) + + // abort if the pause buffer is too large + if (this.pauseBuffer.byteLength > this.maxPauseBufferLength) { + this.abort(new StreamBufferError(`Pause buffer length of ${this.pauseBuffer.byteLength} exceeded limit of ${this.maxPauseBufferLength}`)) + } + } else { + this.abort(new StreamStateError(`Stream readable was "${this.readStatus}" and not "reaable" or "paused"`)) + } + } + + /** + * Receive a reset message - close immediately for reading and writing (remote + * error) + */ + onRemoteReset (): void { + this.log.trace('on remote reset') + + if (this.status === 'closed' || this.status === 'aborted' || this.status === 'reset') { + return + } + + this.status = 'reset' + this.writeStatus = 'closed' + this.remoteWriteStatus = 'closed' + this.remoteReadStatus = 'closed' + + this.timeline.reset = Date.now() + this.timeline.closeWrite = Date.now() + this.timeline.remoteCloseWrite = Date.now() + this.timeline.remoteCloseRead = Date.now() + + if (this.pauseBuffer.byteLength === 0) { + this.readStatus = 'closed' + this.timeline.closeRead = Date.now() + } + + const err = new StreamResetError() + + this.dispatchEvent(new StreamResetEvent(err)) + } + + /** + * Called by extending classes when the remote closed its writable end + */ + onRemoteCloseWrite (): void { + if (this.remoteWriteStatus === 'closed') { + return + } + + this.log.trace('on remote close write - this.writeStatus %s', this.writeStatus) + + this.remoteWriteStatus = 'closed' + this.timeline.remoteCloseWrite = Date.now() + + this.safeDispatchEvent('remoteCloseWrite') + + this.maybeCloseRead() + + if (this.writeStatus === 'closed') { + this.onClosed() + } + } + + /** + * Called by extending classes when the remote closed its readable end + */ + onRemoteCloseRead (): void { + this.log.trace('on remote close read - this.writeStatus %s', this.writeStatus) + + this.remoteReadStatus = 'closed' + this.timeline.remoteCloseRead = Date.now() + + this.safeDispatchEvent('remoteCloseRead') + + if (this.writeStatus === 'closed') { + this.onClosed() + } + } + + /** + * This can be called by extending classes when an underlying transport + * closed. No further messages will be sent or received. + */ + onClosed (): void { + if (this.status !== 'open') { + return + } + + this.status = 'closed' + this.timeline.close = Date.now() + + this.maybeCloseRead() + + setTimeout(() => { + this.dispatchEvent(new StreamCloseEvent()) + }, 0) + } + + private maybeCloseRead (): void { + if (this.readStatus === 'readable' && this.pauseBuffer.byteLength === 0) { + this.readStatus = 'closed' + this.timeline.closeRead = Date.now() + + setTimeout(() => { + this.safeDispatchEvent('closeRead') + }, 0) + } + } + + private processSendQueue (): boolean { + // don't send data if the underlying send buffer is full + if (this.writeStatus === 'paused') { + this.log('pause sending because local write status was "paused"') + return false + } + + if (this.sendQueue.byteLength === 0) { + this.log('not sending because send queue was empty') + return true + } + + const toSend = this.sendQueue.sublist() + const totalBytes = toSend.byteLength + const { sentBytes, canSendMore } = this.sendData(toSend) + this.sendQueue.consume(sentBytes) + + if (!canSendMore) { + this.log('pausing sending because underlying stream is full') + this.writeStatus = 'paused' + return canSendMore + } + + if (sentBytes !== totalBytes) { + this.abort(new Error(`All bytes from current chunk must be sent before continuing - sent ${sentBytes}/${totalBytes}`)) + } + + return canSendMore + } + + private dispatchPauseBuffer (): void { + if (this.pauseBuffer.byteLength === 0) { + return + } + + // discard the pause buffer if our readable end is closed + if (this.readStatus === 'closing' || this.readStatus === 'closed') { + this.pauseBuffer.consume(this.pauseBuffer.byteLength) + } else if (this.readStatus === 'readable') { + const buf = this.pauseBuffer.sublist() + this.pauseBuffer.consume(buf.byteLength) + + this.dispatchEvent(new StreamMessageEvent(buf)) + } + } + + /** + * Send a data message to the remote end of the stream. Implementations of + * this method should return the number of bytes from the passed buffer that + * were sent successfully and if the underlying resource can accept more data. + * + * The implementation should always attempt to send the maximum amount of data + * possible. + * + * Returning a result that means the data was only partially sent but that the + * underlying resource can accept more data is invalid. + */ + abstract sendData (data: Uint8ArrayList): SendResult + + /** + * Send a reset message to the remote end of the stream + */ + abstract sendReset (err: Error): void + + /** + * If supported, instruct the remote end of the stream to temporarily stop + * sending data messages + */ + abstract sendPause (): void + + /** + * If supported, inform the remote end of the stream they may resume sending + * data messages + */ + abstract sendResume (): void + + /** + * Send a message to the remote end of the stream, informing them that we will + * send no more data messages. + */ + abstract sendCloseWrite (options?: AbortOptions): Promise + + /** + * If supported, send a message to the remote end of the stream, informing + * them that we will read no more data messages. + */ + abstract sendCloseRead (options?: AbortOptions): Promise +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-multiaddr-connection.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-multiaddr-connection.ts new file mode 100644 index 000000000..6c1f927dd --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-multiaddr-connection.ts @@ -0,0 +1,47 @@ +import { AbstractMessageStream } from './abstract-message-stream.ts' +import type { MessageStreamInit } from './abstract-message-stream.ts' +import type { CounterGroup, Logger, MultiaddrConnection, MessageStreamDirection } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +export interface AbstractMultiaddrConnectionInit extends Omit { + remoteAddr: Multiaddr + direction: MessageStreamDirection + log: Logger + inactivityTimeout?: number + localAddr?: Multiaddr + metricPrefix?: string + metrics?: CounterGroup +} + +export abstract class AbstractMultiaddrConnection extends AbstractMessageStream implements MultiaddrConnection { + public remoteAddr: Multiaddr + + private metricPrefix: string + private metrics?: CounterGroup + + constructor (init: AbstractMultiaddrConnectionInit) { + super(init) + + this.metricPrefix = init.metricPrefix ?? '' + this.metrics = init.metrics + this.remoteAddr = init.remoteAddr + + this.addEventListener('close', (evt) => { + this.metrics?.increment({ [`${this.metricPrefix}end`]: true }) + + if (evt.error != null) { + if (evt.local) { + this.metrics?.increment({ [`${this.metricPrefix}abort`]: true }) + } else { + this.metrics?.increment({ [`${this.metricPrefix}reset`]: true }) + } + } else { + if (evt.local) { + this.metrics?.increment({ [`${this.metricPrefix}_local_close`]: true }) + } else { + this.metrics?.increment({ [`${this.metricPrefix}_remote_close`]: true }) + } + } + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-stream-muxer.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-stream-muxer.ts new file mode 100644 index 000000000..18aa39adf --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-stream-muxer.ts @@ -0,0 +1,171 @@ +import { MuxerClosedError, TypedEventEmitter } from '@libp2p/interface' +import { raceSignal } from 'race-signal' +import type { AbstractStream } from './abstract-stream.ts' +import type { AbortOptions, CreateStreamOptions, Logger, MessageStream, MultiaddrConnection, Stream, StreamMuxer, StreamMuxerEvents, StreamMuxerStatus } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' +import { isPromise } from './is-promise.ts' + +export interface AbstractStreamMuxerInit { + /** + * The protocol name for the muxer + */ + protocol: string + + /** + * The name of the muxer, used to create a new logging scope from the passed + * connection's logger + */ + name: string +} + +export abstract class AbstractStreamMuxer extends TypedEventEmitter> implements StreamMuxer { + public streams: MuxedStream[] + public protocol: string + public status: StreamMuxerStatus + + protected log: Logger + protected maConn: MessageStream + + constructor (maConn: MessageStream, init: AbstractStreamMuxerInit) { + super() + + this.maConn = maConn + this.protocol = init.protocol + this.streams = [] + this.status = 'open' + this.log = maConn.log.newScope(init.name) + + // read/write all data from/to underlying maConn + this.maConn.addEventListener('message', (evt) => { + try { + this.onData(evt.data) + } catch (err: any) { + this.abort(err) + this.maConn.abort(err) + } + }) + + // close muxer when underlying maConn closes + this.maConn.addEventListener('close', (evt) => { + if (this.status === 'open') { + this.onTransportClosed() + } + }) + + // signal stream writers when the underlying connection can accept more data + this.maConn.addEventListener('drain', () => { + this.log('underlying stream drained, signal %d streams to continue writing', this.streams.length) + + this.streams.forEach(stream => { + stream.safeDispatchEvent('drain') + }) + }) + } + + send (data: Uint8Array | Uint8ArrayList): boolean { + return this.maConn.send(data) + } + + async close (options?: AbortOptions): Promise { + if (this.status === 'closed') { + return + } + + this.status = 'closing' + + await raceSignal(Promise.all( + [...this.streams].map(async s => { + await s.close(options) + }) + ), options?.signal) + + this.status = 'closed' + } + + abort (err: Error): void { + if (this.status === 'closed') { + return + } + + this.status = 'closing' + + ;[...this.streams].forEach(s => { + s.abort(err) + }) + + this.status = 'closed' + } + + onTransportClosed (): void { + this.status = 'closing' + + try { + [...this.streams].forEach(stream => { + stream.onMuxerClosed() + }) + } catch (err: any) { + this.abort(err) + } + + this.status = 'closed' + } + + async createStream (options?: CreateStreamOptions): Promise { + if (this.status !== 'open') { + throw new MuxerClosedError() + } + + let stream = this.onCreateStream(options ?? {}) + + if (isPromise(stream)) { + stream = await stream + } + + this.streams.push(stream) + this.cleanUpStream(stream) + + return stream + } + + /** + * Extending classes should invoke this method when a new stream was created + * by the remote muxer + */ + onRemoteStream (stream: MuxedStream): void { + this.streams.push(stream) + this.cleanUpStream(stream) + + this.safeDispatchEvent('stream', { + detail: stream + }) + } + + private cleanUpStream (stream: Stream): void { + const onEnd = (): void => { + const index = this.streams.findIndex(s => s === stream) + + if (index !== -1) { + this.streams.splice(index, 1) + } + + // TODO: standardise metrics + // this.metrics?.increment({ [`${stream.direction}_stream_end`]: true }) + // this.metrics?.increment({ [`${stream.direction}_stream_error`]: true }) + } + + // TODO: standardise metrics + // this.metrics?.increment({ [`${stream.direction}_stream`]: true }) + + stream.addEventListener('close', onEnd) + } + + /** + * A new outgoing stream needs to be created + */ + abstract onCreateStream (options: CreateStreamOptions): MuxedStream | Promise + + /** + * Multiplexed data was received from the remote muxer + */ + abstract onData (data: Uint8Array | Uint8ArrayList): void +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-stream.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-stream.ts new file mode 100644 index 000000000..579f50b32 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/abstract-stream.ts @@ -0,0 +1,53 @@ +import { pushable } from 'it-pushable' +import { AbstractMessageStream } from './abstract-message-stream.js' +import type { MessageStreamInit } from './abstract-message-stream.js' +import type { Stream, StreamMessageEvent, StreamCloseEvent } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +export interface AbstractStreamInit extends MessageStreamInit { + /** + * A unique identifier for this stream + */ + id: string + + /** + * The protocol name for the stream, if it is known + */ + protocol?: string +} + +export abstract class AbstractStream extends AbstractMessageStream implements Stream { + public id: string + public protocol: string + + constructor (init: AbstractStreamInit) { + super(init) + + this.id = init.id + this.protocol = init.protocol ?? '' + } + + /** + * The muxer this stream was created by has closed - this stream should exit + * without sending any further messages. Any unread data can still be read but + * otherwise this stream is now closed. + */ + onMuxerClosed () { + if (this.remoteReadStatus !== 'closed') { + this.remoteReadStatus = 'closed' + this.timeline.remoteCloseRead = Date.now() + } + + if (this.remoteWriteStatus !== 'closed') { + this.remoteWriteStatus = 'closed' + this.timeline.remoteCloseWrite = Date.now() + } + + if (this.writeStatus !== 'closed') { + this.writeStatus = 'closed' + this.timeline.closeWrite = Date.now() + } + + this.onClosed() + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/adaptive-timeout.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/adaptive-timeout.ts new file mode 100644 index 000000000..94264623b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/adaptive-timeout.ts @@ -0,0 +1,106 @@ +import { anySignal } from 'any-signal' +import { setMaxListeners } from 'main-event' +import { MovingAverage } from './moving-average.js' +import type { MetricGroup, Metrics } from '@libp2p/interface' +import type { ClearableSignal } from 'any-signal' + +export const DEFAULT_TIMEOUT_MULTIPLIER = 1.2 +export const DEFAULT_FAILURE_MULTIPLIER = 2 +export const DEFAULT_MIN_TIMEOUT = 5_000 +export const DEFAULT_MAX_TIMEOUT = 60_000 +export const DEFAULT_INTERVAL = 5_000 + +export interface AdaptiveTimeoutSignal extends ClearableSignal { + start: number + timeout: number +} + +export interface AdaptiveTimeoutInit { + metricName?: string + metrics?: Metrics + interval?: number + timeoutMultiplier?: number + failureMultiplier?: number + minTimeout?: number + maxTimeout?: number +} + +export interface GetTimeoutSignalOptions { + timeoutFactor?: number + signal?: AbortSignal +} + +export class AdaptiveTimeout { + private readonly success: MovingAverage + private readonly failure: MovingAverage + private readonly next: MovingAverage + private readonly metric?: MetricGroup + private readonly timeoutMultiplier: number + private readonly failureMultiplier: number + private readonly minTimeout: number + private readonly maxTimeout: number + + constructor (init: AdaptiveTimeoutInit = {}) { + const interval = init.interval ?? DEFAULT_INTERVAL + this.success = new MovingAverage(interval) + this.failure = new MovingAverage(interval) + this.next = new MovingAverage(interval) + this.failureMultiplier = init.failureMultiplier ?? DEFAULT_FAILURE_MULTIPLIER + this.timeoutMultiplier = init.timeoutMultiplier ?? DEFAULT_TIMEOUT_MULTIPLIER + this.minTimeout = init.minTimeout ?? DEFAULT_MIN_TIMEOUT + this.maxTimeout = init.maxTimeout ?? DEFAULT_MAX_TIMEOUT + + if (init.metricName != null) { + this.metric = init.metrics?.registerMetricGroup(init.metricName) + } + } + + getTimeoutSignal (options: GetTimeoutSignalOptions = {}): AdaptiveTimeoutSignal { + // calculate timeout for individual peers based on moving average of + // previous successful requests + let timeout = Math.round(this.next.movingAverage * (options.timeoutFactor ?? this.timeoutMultiplier)) + + if (timeout < this.minTimeout) { + timeout = this.minTimeout + } + + if (timeout > this.maxTimeout) { + timeout = this.maxTimeout + } + + const sendTimeout = AbortSignal.timeout(timeout) + const timeoutSignal = anySignal([options.signal, sendTimeout]) as AdaptiveTimeoutSignal + setMaxListeners(Infinity, timeoutSignal, sendTimeout) + + timeoutSignal.start = Date.now() + timeoutSignal.timeout = timeout + + return timeoutSignal + } + + cleanUp (signal: AdaptiveTimeoutSignal): void { + const time = Date.now() - signal.start + + if (signal.aborted) { + this.failure.push(time) + this.next.push(time * this.failureMultiplier) + this.metric?.update({ + failureMovingAverage: this.failure.movingAverage, + failureDeviation: this.failure.deviation, + failureForecast: this.failure.forecast, + failureVariance: this.failure.variance, + failure: time + }) + } else { + this.success.push(time) + this.next.push(time) + this.metric?.update({ + successMovingAverage: this.success.movingAverage, + successDeviation: this.success.deviation, + successForecast: this.success.forecast, + successVariance: this.success.variance, + success: time + }) + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/debounce.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/debounce.ts new file mode 100644 index 000000000..9e3adf404 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/debounce.ts @@ -0,0 +1,30 @@ +import type { Startable } from '@libp2p/interface' + +export interface DebouncedFunction extends Startable { + (): void +} + +/** + * Returns a function wrapper that will only call the passed function once + * + * Important - the passed function should not throw or reject + */ +export function debounce (func: () => void | Promise, wait: number): DebouncedFunction { + let timeout: ReturnType | undefined + + const output = function (): void { + const later = function (): void { + timeout = undefined + void func() + } + + clearTimeout(timeout) + timeout = setTimeout(later, wait) + } + output.start = (): void => {} + output.stop = (): void => { + clearTimeout(timeout) + } + + return output +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/errors.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/errors.ts new file mode 100644 index 000000000..60ce7ac6a --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/errors.ts @@ -0,0 +1,34 @@ +import type { RateLimiterResult } from './rate-limiter.js' + +/** + * A rate limit was hit + */ +export class RateLimitError extends Error { + remainingPoints: number + msBeforeNext: number + consumedPoints: number + isFirstInDuration: boolean + + constructor (message = 'Rate limit exceeded', props: RateLimiterResult) { + super(message) + this.name = 'RateLimitError' + this.remainingPoints = props.remainingPoints + this.msBeforeNext = props.msBeforeNext + this.consumedPoints = props.consumedPoints + this.isFirstInDuration = props.isFirstInDuration + } +} + +export class QueueFullError extends Error { + static name = 'QueueFullError' + + constructor (message: string = 'The queue was full') { + super(message) + this.name = 'QueueFullError' + } +} + +export class UnexpectedEOFError extends Error { + static name = 'UnexpectedEOFError' + name = 'UnexpectedEOFError' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/bloom-filter.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/bloom-filter.ts new file mode 100644 index 000000000..070e09e96 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/bloom-filter.ts @@ -0,0 +1,134 @@ +// ported from xxbloom - https://github.com/ceejbot/xxbloom/blob/master/LICENSE +import { randomBytes } from '@libp2p/crypto' +import { Uint8ArrayList } from 'uint8arraylist' +import { alloc } from 'uint8arrays/alloc' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { fnv1a } from './hashes.js' +import type { Filter } from './index.js' + +const LN2_SQUARED = Math.LN2 * Math.LN2 + +export interface BloomFilterOptions { + seeds?: number[] + hashes?: number + bits?: number +} + +export class BloomFilter implements Filter { + public readonly seeds: number[] + public readonly bits: number + public buffer: Uint8Array + + constructor (options: BloomFilterOptions = {}) { + if (options.seeds != null) { + this.seeds = options.seeds + } else { + this.seeds = generateSeeds(options.hashes ?? 8) + } + + this.bits = options.bits ?? 1024 + this.buffer = alloc(Math.ceil(this.bits / 8)) + } + + /** + * Add an item to the filter + */ + add (item: Uint8Array | string): void { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + for (let i = 0; i < this.seeds.length; i++) { + const hash = fnv1a.hash(item, this.seeds[i]) + const bit = hash % this.bits + + this.setbit(bit) + } + } + + /** + * Test if the filter has an item. If it returns false it definitely does not + * have the item. If it returns true, it probably has the item but there's + * an `errorRate` chance it doesn't. + */ + has (item: Uint8Array | string): boolean { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + for (let i = 0; i < this.seeds.length; i++) { + const hash = fnv1a.hash(item, this.seeds[i]) + const bit = hash % this.bits + + const isSet = this.getbit(bit) + + if (!isSet) { + return false + } + } + + return true + } + + /** + * Reset the filter + */ + clear (): void { + this.buffer.fill(0) + } + + setbit (bit: number): void { + const pos = Math.floor(bit / 8) + const shift = bit % 8 + + let bitField = this.buffer[pos] + bitField |= (0x1 << shift) + this.buffer[pos] = bitField + } + + getbit (bit: number): boolean { + const pos = Math.floor(bit / 8) + const shift = bit % 8 + + const bitField = this.buffer[pos] + return (bitField & (0x1 << shift)) !== 0 + } +} + +/** + * Create a `BloomFilter` with the smallest `bits` and `hashes` value for the + * specified item count and error rate. + */ +export function createBloomFilter (itemCount: number, errorRate: number = 0.005): Filter { + const opts = optimize(itemCount, errorRate) + return new BloomFilter(opts) +} + +function optimize (itemCount: number, errorRate: number = 0.005): { bits: number, hashes: number } { + const bits = Math.round(-1 * itemCount * Math.log(errorRate) / LN2_SQUARED) + const hashes = Math.round((bits / itemCount) * Math.LN2) + + return { bits, hashes } +} + +function generateSeeds (count: number): number[] { + let buf: Uint8ArrayList + let j: number + const seeds = [] + + for (let i = 0; i < count; i++) { + buf = new Uint8ArrayList(randomBytes(4)) + seeds[i] = buf.getUint32(0, true) + + // Make sure we don't end up with two identical seeds, + // which is unlikely but possible. + for (j = 0; j < i; j++) { + if (seeds[i] === seeds[j]) { + i-- + break + } + } + } + + return seeds +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/bucket.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/bucket.ts new file mode 100644 index 000000000..5462c1394 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/bucket.ts @@ -0,0 +1,64 @@ +import { Fingerprint } from './fingerprint.js' +import { getRandomInt } from './utils.js' + +export class Bucket { + private readonly contents: Array + + constructor (size: number) { + this.contents = new Array(size).fill(null) + } + + has (fingerprint: Fingerprint): boolean { + if (!(fingerprint instanceof Fingerprint)) { + throw new TypeError('Invalid Fingerprint') + } + + return this.contents.some((fp) => { + return fingerprint.equals(fp) + }) + } + + add (fingerprint: Fingerprint): boolean { + if (!(fingerprint instanceof Fingerprint)) { + throw new TypeError('Invalid Fingerprint') + } + + for (let i = 0; i < this.contents.length; i++) { + if (this.contents[i] == null) { + this.contents[i] = fingerprint + return true + } + } + + return true + } + + swap (fingerprint: Fingerprint): Fingerprint | null { + if (!(fingerprint instanceof Fingerprint)) { + throw new TypeError('Invalid Fingerprint') + } + + const i = getRandomInt(0, this.contents.length - 1) + const current = this.contents[i] + this.contents[i] = fingerprint + + return current + } + + remove (fingerprint: Fingerprint): boolean { + if (!(fingerprint instanceof Fingerprint)) { + throw new TypeError('Invalid Fingerprint') + } + + const found = this.contents.findIndex((fp) => { + return fingerprint.equals(fp) + }) + + if (found > -1) { + this.contents[found] = null + return true + } else { + return false + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/cuckoo-filter.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/cuckoo-filter.ts new file mode 100644 index 000000000..d4383477d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/cuckoo-filter.ts @@ -0,0 +1,198 @@ +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { Bucket } from './bucket.js' +import { Fingerprint, MAX_FINGERPRINT_SIZE } from './fingerprint.js' +import { fnv1a } from './hashes.js' +import { getRandomInt } from './utils.js' +import type { Hash } from './hashes.js' +import type { Filter } from './index.js' + +const maxCuckooCount = 500 + +export interface CuckooFilterInit { + /** + * How many items the filter is expected to contain + */ + filterSize: number + + /** + * How many items to put in each bucket + */ + bucketSize?: number + + /** + * How many bytes the fingerprint is expected to be + */ + fingerprintSize?: number + + /** + * A non-cryptographic hash implementation + */ + hash?: Hash + + /** + * A number used to seed the hash + */ + seed?: number +} + +export class CuckooFilter implements Filter { + private readonly bucketSize: number + private readonly filterSize: number + private readonly fingerprintSize: number + private readonly buckets: Bucket[] + public count: number + private readonly hash: Hash + private readonly seed: number + + constructor (init: CuckooFilterInit) { + this.filterSize = init.filterSize + this.bucketSize = init.bucketSize ?? 4 + this.fingerprintSize = init.fingerprintSize ?? 2 + this.count = 0 + this.buckets = [] + this.hash = init.hash ?? fnv1a + this.seed = init.seed ?? getRandomInt(0, Math.pow(2, 10)) + } + + add (item: Uint8Array | string): boolean { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + const fingerprint = new Fingerprint(item, this.hash, this.seed, this.fingerprintSize) + const j = this.hash.hash(item, this.seed) % this.filterSize + const k = (j ^ fingerprint.hash()) % this.filterSize + + if (this.buckets[j] == null) { + this.buckets[j] = new Bucket(this.bucketSize) + } + + if (this.buckets[k] == null) { + this.buckets[k] = new Bucket(this.bucketSize) + } + + if (this.buckets[j].add(fingerprint) || this.buckets[k].add(fingerprint)) { + this.count++ + return true + } + + const rand = [j, k] + let i = rand[getRandomInt(0, rand.length - 1)] + + if (this.buckets[i] == null) { + this.buckets[i] = new Bucket(this.bucketSize) + } + + for (let n = 0; n < maxCuckooCount; n++) { + const swapped = this.buckets[i].swap(fingerprint) + + if (swapped == null) { + continue + } + + i = (i ^ swapped.hash()) % this.filterSize + + if (this.buckets[i] == null) { + this.buckets[i] = new Bucket(this.bucketSize) + } + + if (this.buckets[i].add(swapped)) { + this.count++ + + return true + } else { + continue + } + } + + return false + } + + has (item: Uint8Array | string): boolean { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + const fingerprint = new Fingerprint(item, this.hash, this.seed, this.fingerprintSize) + const j = this.hash.hash(item, this.seed) % this.filterSize + const inJ = this.buckets[j]?.has(fingerprint) ?? false + + if (inJ) { + return inJ + } + + const k = (j ^ fingerprint.hash()) % this.filterSize + + return this.buckets[k]?.has(fingerprint) ?? false + } + + remove (item: Uint8Array | string): boolean { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + const fingerprint = new Fingerprint(item, this.hash, this.seed, this.fingerprintSize) + const j = this.hash.hash(item, this.seed) % this.filterSize + const inJ = this.buckets[j]?.remove(fingerprint) ?? false + + if (inJ) { + this.count-- + return inJ + } + + const k = (j ^ fingerprint.hash()) % this.filterSize + const inK = this.buckets[k]?.remove(fingerprint) ?? false + + if (inK) { + this.count-- + } + + return inK + } + + get reliable (): boolean { + return Math.floor(100 * (this.count / this.filterSize)) <= 90 + } +} + +// max load constants, defined in the cuckoo paper +const MAX_LOAD = { + 1: 0.5, + 2: 0.84, + 4: 0.95, + 8: 0.98 +} + +function calculateBucketSize (errorRate: number = 0.001): 2 | 4 | 8 { + if (errorRate > 0.002) { + return 2 + } + + if (errorRate > 0.00001) { + return 4 + } + + return 8 +} + +export function optimize (maxItems: number, errorRate: number = 0.001): CuckooFilterInit { + // https://www.eecs.harvard.edu/~michaelm/postscripts/cuckoo-conext2014.pdf + // Section 5.1 Optimal Bucket Size + const bucketSize = calculateBucketSize(errorRate) + const load = MAX_LOAD[bucketSize] + + // https://stackoverflow.com/questions/57555236/how-to-size-a-cuckoo-filter/57617208#57617208 + const filterSize = Math.round(maxItems / load) + const fingerprintSize = Math.min(Math.ceil(Math.log2(1 / errorRate) + Math.log2(2 * bucketSize)), MAX_FINGERPRINT_SIZE) + + return { + filterSize, + bucketSize, + fingerprintSize + } +} + +export function createCuckooFilter (maxItems: number, errorRate: number = 0.005): Filter { + const opts = optimize(maxItems, errorRate) + return new CuckooFilter(opts) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/fingerprint.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/fingerprint.ts new file mode 100644 index 000000000..d8c05fbd9 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/fingerprint.ts @@ -0,0 +1,44 @@ +import { alloc as uint8ArrayAlloc } from 'uint8arrays/alloc' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import type { Hash } from './hashes.js' + +export const MAX_FINGERPRINT_SIZE = 64 + +export class Fingerprint { + private readonly fp: Uint8Array + private readonly h: Hash + private readonly seed: number + + constructor (buf: Uint8Array, hash: Hash, seed: number, fingerprintSize: number = 2) { + if (fingerprintSize > MAX_FINGERPRINT_SIZE) { + throw new TypeError('Invalid Fingerprint Size') + } + + const fnv = hash.hashV(buf, seed) + const fp = uint8ArrayAlloc(fingerprintSize) + + for (let i = 0; i < fp.length; i++) { + fp[i] = fnv[i] + } + + if (fp.length === 0) { + fp[0] = 7 + } + + this.fp = fp + this.h = hash + this.seed = seed + } + + hash (): number { + return this.h.hash(this.fp, this.seed) + } + + equals (other?: any): boolean { + if (!(other?.fp instanceof Uint8Array)) { + return false + } + + return uint8ArrayEquals(this.fp, other.fp) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/hashes.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/hashes.ts new file mode 100644 index 000000000..1590d66a3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/hashes.ts @@ -0,0 +1,28 @@ +import fnv1aHash from '@sindresorhus/fnv1a' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' + +export interface Hash { + hash(input: Uint8Array, seed: number): number + hashV(input: Uint8Array, seed: number): Uint8Array +} + +export const fnv1a: Hash = { + hash: (input) => { + return Number(fnv1aHash(input, { + size: 32 + })) + }, + hashV: (input, seed) => { + return numberToBuffer(fnv1a.hash(input, seed)) + } +} + +export function numberToBuffer (num: bigint | number): Uint8Array { + let hex = num.toString(16) + + if (hex.length % 2 === 1) { + hex = `0${hex}` + } + + return uint8ArrayFromString(hex, 'base16') +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/index.ts new file mode 100644 index 000000000..20c911a05 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/index.ts @@ -0,0 +1,12 @@ +export { BloomFilter, createBloomFilter, type BloomFilterOptions } from './bloom-filter.js' +export { CuckooFilter, createCuckooFilter, type CuckooFilterInit } from './cuckoo-filter.js' +export { ScalableCuckooFilter, createScalableCuckooFilter, type ScalableCuckooFilterInit } from './scalable-cuckoo-filter.js' +export type { Bucket } from './bucket.js' +export type { Fingerprint } from './fingerprint.js' +export type { Hash } from './hashes.js' + +export interface Filter { + add(item: Uint8Array | string): void + has(item: Uint8Array | string): boolean + remove?(buf: Uint8Array | string): boolean +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/scalable-cuckoo-filter.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/scalable-cuckoo-filter.ts new file mode 100644 index 000000000..e82ee90e6 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/scalable-cuckoo-filter.ts @@ -0,0 +1,113 @@ +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { CuckooFilter, optimize } from './cuckoo-filter.js' +import { fnv1a } from './hashes.js' +import { getRandomInt } from './utils.js' +import type { CuckooFilterInit } from './cuckoo-filter.js' +import type { Hash } from './hashes.js' +import type { Filter } from './index.js' + +export interface ScalableCuckooFilterInit extends CuckooFilterInit { + /** + * A number to multiply maxItems by when adding new sub-filters + */ + scale?: number +} + +export class ScalableCuckooFilter implements Filter { + private readonly filterSize: number + private readonly bucketSize: number + private readonly fingerprintSize: number + private readonly scale: number + private readonly filterSeries: CuckooFilter[] + private readonly hash: Hash + private readonly seed: number + + constructor (init: ScalableCuckooFilterInit) { + this.bucketSize = init.bucketSize ?? 4 + this.filterSize = init.filterSize ?? (1 << 18) / this.bucketSize + this.fingerprintSize = init.fingerprintSize ?? 2 + this.scale = init.scale ?? 2 + this.hash = init.hash ?? fnv1a + this.seed = init.seed ?? getRandomInt(0, Math.pow(2, 10)) + this.filterSeries = [ + new CuckooFilter({ + filterSize: this.filterSize, + bucketSize: this.bucketSize, + fingerprintSize: this.fingerprintSize, + hash: this.hash, + seed: this.seed + }) + ] + } + + add (item: Uint8Array | string): boolean { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + if (this.has(item)) { + return true + } + + let current = this.filterSeries.find((cuckoo) => { + return cuckoo.reliable + }) + + if (current == null) { + const curSize = this.filterSize * Math.pow(this.scale, this.filterSeries.length) + + current = new CuckooFilter({ + filterSize: curSize, + bucketSize: this.bucketSize, + fingerprintSize: this.fingerprintSize, + hash: this.hash, + seed: this.seed + }) + + this.filterSeries.push(current) + } + + return current.add(item) + } + + has (item: Uint8Array | string): boolean { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + for (let i = 0; i < this.filterSeries.length; i++) { + if (this.filterSeries[i].has(item)) { + return true + } + } + + return false + } + + remove (item: Uint8Array | string): boolean { + if (typeof item === 'string') { + item = uint8ArrayFromString(item) + } + + for (let i = 0; i < this.filterSeries.length; i++) { + if (this.filterSeries[i].remove(item)) { + return true + } + } + + return false + } + + get count (): number { + return this.filterSeries.reduce((acc, curr) => { + return acc + curr.count + }, 0) + } +} + +export function createScalableCuckooFilter (maxItems: number, errorRate: number = 0.001, options?: Pick): Filter { + return new ScalableCuckooFilter({ + ...optimize(maxItems, errorRate), + ...(options ?? {}) + }) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/utils.ts new file mode 100644 index 000000000..732025ca3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/filters/utils.ts @@ -0,0 +1,3 @@ +export function getRandomInt (min: number, max: number): number { + return Math.floor(Math.random() * (max - min)) + min +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/get-thin-waist-addresses.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/get-thin-waist-addresses.browser.ts new file mode 100644 index 000000000..9dd502d51 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/get-thin-waist-addresses.browser.ts @@ -0,0 +1,20 @@ +import { multiaddr } from '@multiformats/multiaddr' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * Get all thin waist addresses on the current host that match the family of the + * passed multiaddr and optionally override the port. + * + * Wildcard IP4/6 addresses will be expanded into all available interfaces. + */ +export function getThinWaistAddresses (ma?: Multiaddr, port?: number): Multiaddr[] { + if (ma == null) { + return [] + } + + const options = ma.toOptions() + + return [ + multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${port ?? options.port}`) + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/get-thin-waist-addresses.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/get-thin-waist-addresses.ts new file mode 100644 index 000000000..390e4bff2 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/get-thin-waist-addresses.ts @@ -0,0 +1,59 @@ +import os from 'node:os' +import { multiaddr } from '@multiformats/multiaddr' +import { isLinkLocalIp } from './link-local-ip.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +const FAMILIES = { 4: 'IPv4', 6: 'IPv6' } + +function isWildcard (ip: string): boolean { + return ['0.0.0.0', '::'].includes(ip) +} + +function getNetworkAddrs (family: 4 | 6): string[] { + const addresses: string[] = [] + const networks = os.networkInterfaces() + + for (const [, netAddrs] of Object.entries(networks)) { + if (netAddrs != null) { + for (const netAddr of netAddrs) { + if (isLinkLocalIp(netAddr.address)) { + continue + } + + if (netAddr.family === FAMILIES[family]) { + addresses.push(netAddr.address) + } + } + } + } + + return addresses +} + +/** + * Get all thin waist addresses on the current host that match the family of the + * passed multiaddr and optionally override the port. + * + * Wildcard IP4/6 addresses will be expanded into all available interfaces. + */ +export function getThinWaistAddresses (ma?: Multiaddr, port?: number): Multiaddr[] { + if (ma == null) { + return [] + } + + const options = ma.toOptions() + + if (isWildcard(options.host)) { + const addrs = [] + + for (const host of getNetworkAddrs(options.family)) { + addrs.push(multiaddr(`/ip${options.family}/${host}/${options.transport}/${port ?? options.port}`)) + } + + return addrs + } + + return [ + multiaddr(`/ip${options.family}/${options.host}/${options.transport}/${port ?? options.port}`) + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/global-unicast-ip.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/global-unicast-ip.ts new file mode 100644 index 000000000..22a8d0d53 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/global-unicast-ip.ts @@ -0,0 +1,10 @@ +import { isIPv6 } from '@chainsafe/is-ip' +import { cidrContains } from '@chainsafe/netmask' + +export function isGlobalUnicastIp (ip: string): boolean { + if (isIPv6(ip)) { + return cidrContains('2000::/3', ip) + } + + return false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/index.ts new file mode 100644 index 000000000..db406d747 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/index.ts @@ -0,0 +1,39 @@ +/** + * @packageDocumentation + * + * This module contains utility functions used by libp2p modules. + */ + +export * from './filters/index.js' +export * from './multiaddr/index.js' +export * from './queue/index.js' +export * from './abstract-message-stream.js' +export * from './abstract-multiaddr-connection.js' +export * from './abstract-stream-muxer.js' +export * from './abstract-stream.js' +export * from './adaptive-timeout.js' +export * from './debounce.js' +export * from './errors.js' +export * from './get-thin-waist-addresses.js' +export * from './global-unicast-ip.js' +export * from './ip-port-to-multiaddr.js' +export * from './is-async-generator.js' +export * from './is-generator.js' +export * from './is-promise.js' +export * from './length-prefixed-decoder.js' +export * from './link-local-ip.js' +export * from './merge-options.js' +export * from './mock-muxer.js' +export * from './mock-stream.js' +export * from './moving-average.js' +export * from './multiaddr-connection-pair.js' +export * from './peer-queue.js' +export * from './priority-queue.js' +export * from './private-ip.js' +export * from './rate-limiter.js' +export * from './repeating-task.js' +export * from './stream-pair.js' +export * from './stream-utils.js' +export * from './socket-writer.js' +export * from './tracked-list.js' +export * from './tracked-map.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/ip-port-to-multiaddr.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/ip-port-to-multiaddr.ts new file mode 100644 index 000000000..1ffddb7f1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/ip-port-to-multiaddr.ts @@ -0,0 +1,31 @@ +import { isIPv4, isIPv6 } from '@chainsafe/is-ip' +import { InvalidParametersError } from '@libp2p/interface' +import { multiaddr } from '@multiformats/multiaddr' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * Transform an IP, Port pair into a multiaddr + */ +export function ipPortToMultiaddr (ip: string, port: number | string): Multiaddr { + if (typeof ip !== 'string') { + throw new InvalidParametersError(`invalid ip provided: ${ip}`) + } + + if (typeof port === 'string') { + port = parseInt(port) + } + + if (isNaN(port)) { + throw new InvalidParametersError(`invalid port provided: ${port}`) + } + + if (isIPv4(ip)) { + return multiaddr(`/ip4/${ip}/tcp/${port}`) + } + + if (isIPv6(ip)) { + return multiaddr(`/ip6/${ip}/tcp/${port}`) + } + + throw new InvalidParametersError(`invalid ip:port for creating a multiaddr: ${ip}:${port}`) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-async-generator.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-async-generator.ts new file mode 100644 index 000000000..57a4a9ed1 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-async-generator.ts @@ -0,0 +1,16 @@ +export function isAsyncGenerator (obj: unknown): obj is AsyncGenerator { + if (obj == null) { + return false + } + + const asyncIterator = (obj as { [Symbol.asyncIterator]?: unknown })?.[ + Symbol.asyncIterator + ] + + if (typeof asyncIterator !== 'function') { + return false + } + + const instance = obj as { next?: unknown } + return typeof instance.next === 'function' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-generator.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-generator.ts new file mode 100644 index 000000000..6307cd445 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-generator.ts @@ -0,0 +1,15 @@ +export function isGenerator (obj: unknown): obj is Generator { + if (obj == null) { + return false + } + + const iterator = (obj as { [Symbol.iterator]?: unknown })?.[Symbol.iterator] + + if (typeof iterator !== 'function') { + return false + } + + const instance = obj as { next?: unknown } + + return typeof instance.next === 'function' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-promise.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-promise.ts new file mode 100644 index 000000000..9a9478a37 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/is-promise.ts @@ -0,0 +1,9 @@ +export function isPromise (thing: any): thing is Promise { + if (thing == null) { + return false + } + + return typeof thing.then === 'function' && + typeof thing.catch === 'function' && + typeof thing.finally === 'function' +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/length-prefixed-decoder.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/length-prefixed-decoder.ts new file mode 100644 index 000000000..4203024ef --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/length-prefixed-decoder.ts @@ -0,0 +1,98 @@ +import { InvalidParametersError } from "@libp2p/interface" +import { Uint8ArrayList } from "uint8arraylist" +import * as varint from 'uint8-varint' +import { InvalidMessageLengthError } from "./stream-utils.ts" + +const DEFAULT_MAX_BUFFER_SIZE = 1024 * 1024 * 4 +const DEFAULT_MAX_DATA_LENGTH = 1024 * 1024 * 4 + +export interface LengthPrefixedDecoderInit { + /** + * How large the internal buffer is allowed to grow - attempting to store more + * data than this will throw + */ + maxBufferSize?: number + + /** + * Throw an error if the message that would be read from the buffer is larger + * than this value + */ + maxDataLength?: number + + /** + * Read a varint from the buffer + */ + lengthDecoder?: (data: Uint8ArrayList | Uint8Array) => number + + /** + * Return how many bytes it takes to encode the passed value + */ + encodingLength?: (length: number) => number +} + +/** + * Decode length-prefixed data from a buffer + */ +export class LengthPrefixedDecoder { + private readonly buffer: Uint8ArrayList + private readonly maxBufferSize: number + private readonly lengthDecoder: (data: Uint8ArrayList | Uint8Array) => number + private readonly maxDataLength: number + private readonly encodingLength: (length: number) => number + + constructor (init: LengthPrefixedDecoderInit = {}) { + this.buffer = new Uint8ArrayList() + this.maxBufferSize = init.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE + this.maxDataLength = init.maxDataLength ?? DEFAULT_MAX_DATA_LENGTH + this.lengthDecoder = init.lengthDecoder ?? varint.decode + this.encodingLength = init.encodingLength ?? varint.encodingLength + } + + /** + * Decodes length-prefixed data + */ + * decode (buf: Uint8Array | Uint8ArrayList): Generator { + this.buffer.append(buf) + + if (this.buffer.byteLength > this.maxBufferSize) { + throw new InvalidParametersError(`Buffer length limit exceeded - ${this.buffer.byteLength}/${this.maxBufferSize}`) + } + + // Loop to consume as many bytes from the buffer as possible + // Eg: when a single chunk contains several frames + while (true) { + let dataLength: number + + try { + dataLength = this.lengthDecoder(this.buffer) + } catch (err) { + if (err instanceof RangeError) { + // ignore errors where we don't have enough data to read the length + // prefix + break + } + + throw err + } + + if (dataLength < 0 || dataLength > this.maxDataLength) { + throw new InvalidMessageLengthError('Invalid message length') + } + + const lengthLength = this.encodingLength(dataLength) + const chunkLength = lengthLength + dataLength + + if (this.buffer.byteLength >= chunkLength) { + const buf = this.buffer.sublist(lengthLength, chunkLength) + + this.buffer.consume(chunkLength) + + if (buf.byteLength > 0) { + yield buf + } + } else { + break + } + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/link-local-ip.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/link-local-ip.ts new file mode 100644 index 000000000..558d7bbc5 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/link-local-ip.ts @@ -0,0 +1,11 @@ +export function isLinkLocalIp (ip: string): boolean { + if (ip.startsWith('169.254.')) { + return true + } + + if (ip.toLowerCase().startsWith('fe80')) { + return true + } + + return false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/merge-options.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/merge-options.ts new file mode 100644 index 000000000..bbffdf7ad --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/merge-options.ts @@ -0,0 +1,161 @@ +import isOptionObject from 'is-plain-obj' + +const { hasOwnProperty } = Object.prototype +const { propertyIsEnumerable } = Object +const defineProperty = (object: any, name: any, value: any): void => { + Object.defineProperty(object, name, { + value, + writable: true, + enumerable: true, + configurable: true + }) +} + +const globalThis = this +const defaultMergeOptions = { + concatArrays: false, + ignoreUndefined: false +} + +const getEnumerableOwnPropertyKeys = (value: any): any[] => { + const keys = [] + + for (const key in value) { + if (hasOwnProperty.call(value, key)) { + keys.push(key) + } + } + + /* istanbul ignore else */ + if (Object.getOwnPropertySymbols) { + const symbols = Object.getOwnPropertySymbols(value) + + for (const symbol of symbols) { + if (propertyIsEnumerable.call(value, symbol)) { + keys.push(symbol) + } + } + } + + return keys +} + +function clone (value: T): T +function clone (value: T[]): T[] +function clone (value: any): any { + if (Array.isArray(value)) { + return cloneArray(value) + } + + if (isOptionObject(value)) { + return cloneOptionObject(value) + } + + return value +} + +function cloneArray (array: T[]): T[] { + const result = array.slice(0, 0) + + getEnumerableOwnPropertyKeys(array).forEach(key => { + defineProperty(result, key, clone(array[key])) + }) + + return result +} + +function cloneOptionObject (object: any): any { + const result = Object.getPrototypeOf(object) === null ? Object.create(null) : {} + + getEnumerableOwnPropertyKeys(object).forEach(key => { + defineProperty(result, key, clone(object[key])) + }) + + return result +} + +const mergeKeys = (merged: any, source: any, keys: any[], config: any): any => { + keys.forEach(key => { + if (typeof source[key] === 'undefined' && config.ignoreUndefined) { + return + } + + // Do not recurse into prototype chain of merged + if (key in merged && merged[key] !== Object.getPrototypeOf(merged)) { + defineProperty(merged, key, merge(merged[key], source[key], config)) + } else { + defineProperty(merged, key, clone(source[key])) + } + }) + + return merged +} + +/** + * see [Array.prototype.concat ( ...arguments )](http://www.ecma-international.org/ecma-262/6.0/#sec-array.prototype.concat) + */ +const concatArrays = (merged: any, source: any, config: any): any => { + let result = merged.slice(0, 0) + let resultIndex = 0; + + [merged, source].forEach(array => { + const indices: any[] = [] + + // `result.concat(array)` with cloning + for (let k = 0; k < array.length; k++) { + if (!hasOwnProperty.call(array, k)) { + continue + } + + indices.push(String(k)) + + if (array === merged) { + // Already cloned + defineProperty(result, resultIndex++, array[k]) + } else { + defineProperty(result, resultIndex++, clone(array[k])) + } + } + + // Merge non-index keys + result = mergeKeys(result, array, getEnumerableOwnPropertyKeys(array).filter(key => !indices.includes(key)), config) + }) + + return result +} + +function merge (merged: any, source: any, config: any): any { + if (config.concatArrays && Array.isArray(merged) && Array.isArray(source)) { + return concatArrays(merged, source, config) + } + + if (!isOptionObject(source) || !isOptionObject(merged)) { + return clone(source) + } + + return mergeKeys(merged, source, getEnumerableOwnPropertyKeys(source), config) +} + +/** + * Port of `merge-options` to typescript + * + * @see https://github.com/schnittstabil/merge-options/pull/28 + */ +export function mergeOptions (this: any, ...options: any[]): any { + const config = merge(clone(defaultMergeOptions), (this !== globalThis && this) || {}, defaultMergeOptions) + let merged = { _: {} } + + for (const option of options) { + if (option === undefined) { + continue + } + + if (!isOptionObject(option)) { + throw new TypeError('`' + option + '` is not an Option Object') + } + + merged = merge(merged, { _: option }, config) + } + + return merged._ +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/message-queue.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/message-queue.ts new file mode 100644 index 000000000..7c74e46a0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/message-queue.ts @@ -0,0 +1,94 @@ +import delay from 'delay' +import { TypedEventEmitter } from 'main-event' +import { Queue } from './queue/index.js' +import type { Logger } from '@libp2p/interface' + +export interface MessageQueueMessages { + /** + * Emitted when the queue is empty + */ + drain: Event +} + +export interface MessageQueueInit { + /** + * How much delay there should be between each message send in ms (note that + * even 0 introduces a small delay) + * + * @default 0 + */ + delay?: number + + /** + * How many messages to hold in the send queue before applying backpressure to + * the sender + */ + capacity?: number +} + +/** + * Accepts events to emit after a short delay, and with a configurable maximum + * queue capacity after which the send method will return false to let us + * simulate write backpressure. + */ +export class MessageQueue extends TypedEventEmitter { + private queue: Queue + private capacity: number + private delay: number + private needsDrain: boolean + private log: Logger + + constructor (init: MessageQueueInit & { log: Logger }) { + super() + + this.needsDrain = false + this.queue = new Queue({ + concurrency: 1 + }) + this.capacity = init.capacity ?? 5 + this.delay = init.delay ?? 0 + this.log = init.log + + this.queue.addEventListener('idle', () => { + if (this.needsDrain) { + this.log('network send queue drained') + this.safeDispatchEvent('drain') + this.needsDrain = false + } + }) + } + + send (evt: Event): boolean { + this.queue.add(async () => { + if (this.delay > 0) { + await delay(this.delay) + } + + this.dispatchEvent(evt) + }) + + if (this.queue.size >= this.capacity) { + this.log('network send queue full') + this.needsDrain = true + return false + } + + return true + } + + pause (): void { + this.queue.pause() + } + + resume (): void { + this.queue.resume() + } + + onIdle (): Promise { + return this.queue.onIdle() + } + + size (): number { + return this.queue.size + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/mock-muxer.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/mock-muxer.ts new file mode 100644 index 000000000..202c49f53 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/mock-muxer.ts @@ -0,0 +1,280 @@ +import * as lp from 'it-length-prefixed' +import { pushable } from 'it-pushable' +import { Uint8ArrayList } from 'uint8arraylist' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { toString as uint8ArrayToString } from 'uint8arrays/to-string' +import { AbstractStreamMuxer } from './abstract-stream-muxer.ts' +import { AbstractStream } from './abstract-stream.ts' +import { Queue } from './queue/index.js' +import type { SendResult } from './abstract-message-stream.ts' +import type { AbstractStreamInit } from './abstract-stream.ts' +import type { AbortOptions, MessageStreamDirection, CreateStreamOptions, StreamMuxerFactory, StreamMuxer, MultiaddrConnection } from '@libp2p/interface' +import type { Pushable } from 'it-pushable' +import type { SupportedEncodings } from 'uint8arrays/from-string' + +let streams = 0 + +interface DataMessage { + id: string + type: 'data' + chunk: string +} + +interface ResetMessage { + id: string + type: 'reset' +} + +interface CloseWriteMessage { + id: string + type: 'closeWrite' +} + +interface CloseReadMessage { + id: string + type: 'closeRead' +} + +interface CreateMessage { + id: string + type: 'create' + protocol?: string +} + +interface PauseMessage { + id: string + type: 'pause' +} + +interface ResumeMessage { + id: string + type: 'resume' +} + +type StreamMessage = DataMessage | ResetMessage | CloseWriteMessage | CloseReadMessage | CreateMessage | PauseMessage | ResumeMessage + +export interface MockMuxedStreamInit extends AbstractStreamInit { + sendMessage(message: StreamMessage): boolean + encoding: SupportedEncodings +} + +class MockMuxedStream extends AbstractStream { + private readonly sendMessage: (message: StreamMessage) => boolean + private dataQueue: Queue + private encoding: SupportedEncodings + + constructor (init: MockMuxedStreamInit) { + super(init) + + this.sendMessage = init.sendMessage + this.encoding = init.encoding + this.dataQueue = new Queue({ + concurrency: 1 + }) + + if (this.direction === 'outbound') { + this.sendMessage({ + id: this.id, + type: 'create', + protocol: this.protocol + }) + } + } + + sendData (data: Uint8ArrayList): SendResult { + const canSendMore = this.sendMessage({ + id: this.id, + type: 'data', + chunk: uint8ArrayToString(data.subarray(), this.encoding) + }) + + return { + sentBytes: data.byteLength, + canSendMore + } + } + + sendReset (): void { + this.sendMessage({ + id: this.id, + type: 'reset' + }) + } + + async sendCloseWrite (options?: AbortOptions): Promise { + this.sendMessage({ + id: this.id, + type: 'closeWrite' + }) + + options?.signal?.throwIfAborted() + } + + async sendCloseRead (options?: AbortOptions): Promise { + this.sendMessage({ + id: this.id, + type: 'closeRead' + }) + + options?.signal?.throwIfAborted() + } + + sendPause (): void { + this.sendMessage({ + id: this.id, + type: 'pause' + }) + } + + sendResume (): void { + this.sendMessage({ + id: this.id, + type: 'resume' + }) + } + + onRemotePaused (): void { + // console.info('remote pasued') + this.dataQueue.pause() + } + + onRemoteResumed (): void { + // console.info('remote resumved') + this.dataQueue.resume() + } +} + +interface MockMuxerInit { + /** + * How long the input queue can grow + */ + maxInputQueueSize?: number + + /** + * How to encode data message + * + * @default base64 + */ + encoding?: SupportedEncodings +} + +class MockMuxer extends AbstractStreamMuxer { + private input: Pushable + private maxInputQueueSize: number + private encoding: SupportedEncodings + + constructor (maConn: MultiaddrConnection, init: MockMuxerInit) { + super(maConn, { + ...init, + protocol: '/mock-muxer/1.0.0', + name: 'mock-muxer' + }) + + this.maxInputQueueSize = init.maxInputQueueSize ?? 1024 * 1024 * 10 + this.encoding = init.encoding ?? 'base64' + this.input = pushable() + this.sendMessage = this.sendMessage.bind(this) + + Promise.resolve() + .then(async () => { + for await (const buf of lp.decode(this.input)) { + this.onMessage(JSON.parse(uint8ArrayToString(buf.subarray()))) + } + }) + .catch(err => { + this.abort(err) + }) + } + + onData (data: Uint8Array | Uint8ArrayList): void { + if (this.input.readableLength >= this.maxInputQueueSize) { + this.abort(new Error(`Input queue exceeded maximum size ${this.input.readableLength} >= ${this.maxInputQueueSize}`)) + return + } + + this.input.push(data) + } + + sendMessage (message: StreamMessage): boolean { + this.log('send message %o', message) + + const json = JSON.stringify(message) + const buf = uint8ArrayFromString(json) + const encoded = lp.encode.single(buf) + + return this.send(encoded) + } + + onMessage (message: StreamMessage): void { + this.log('incoming message %o', message) + let stream: MockMuxedStream | undefined = this.streams.find(s => s.id === message.id) + + if (message.type === 'create') { + if (stream != null) { + throw new Error(`Already had stream for ${message.id}`) + } + + this.log('create stream inbound %s', message.id) + stream = this._createStream(message.id, 'inbound', { + protocol: message.protocol + }) + + this.onRemoteStream(stream) + } + + if (stream == null) { + this.log.error(`No stream found for ${message.id}`) + return + } + + if (message.type === 'data') { + stream.onData(uint8ArrayFromString(message.chunk, this.encoding)) + } else if (message.type === 'reset') { + stream.onRemoteReset() + } else if (message.type === 'closeWrite') { + stream.onRemoteCloseWrite() + } else if (message.type === 'closeRead') { + stream.onRemoteCloseRead() + } else if (message.type === 'pause') { + stream.onRemotePaused() + } else if (message.type === 'resume') { + stream.onRemoteResumed() + } + } + + onCreateStream (options: CreateStreamOptions): MockMuxedStream { + return this._createStream(`${streams++}`, 'outbound', options) + } + + _createStream (id: string, direction: MessageStreamDirection, options: CreateStreamOptions): MockMuxedStream { + this.log('createStream %s %s', direction, id) + + return new MockMuxedStream({ + ...options, + id, + direction, + log: this.log.newScope(`stream:${direction}:${id}`), + sendMessage: this.sendMessage, + encoding: this.encoding + }) + } +} + +class MockMuxerFactory implements StreamMuxerFactory { + public protocol: string = '/mock-muxer/1.0.0' + private init: MockMuxerInit + + constructor (init: MockMuxerInit) { + this.init = init + } + + createStreamMuxer (maConn: MultiaddrConnection): StreamMuxer { + return new MockMuxer(maConn, { + ...this.init + }) + } +} + +export function mockMuxer (init: MockMuxerInit = {}): StreamMuxerFactory { + return new MockMuxerFactory(init) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/mock-stream.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/mock-stream.ts new file mode 100644 index 000000000..1c945b9ca --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/mock-stream.ts @@ -0,0 +1,113 @@ +import { StreamMessageEvent } from '@libp2p/interface' +import { defaultLogger } from '@libp2p/logger' +import { raceSignal } from 'race-signal' +import { AbstractStream } from './abstract-stream.ts' +import type { SendResult } from './abstract-message-stream.ts' +import type { MessageQueue } from './message-queue.ts' +import type { AbortOptions, MessageStreamDirection, TypedEventTarget } from '@libp2p/interface' +import type { Uint8ArrayList } from 'uint8arraylist' + +interface MockStreamMessages { + message: MessageEvent + reset: Event + closeWrite: Event + closeRead: Event +} + +interface MockStreamInit { + delay?: number + direction: MessageStreamDirection + local: MessageQueue + remote: TypedEventTarget +} + +let streamId = 0 + +export class MockStream extends AbstractStream { + private local: MessageQueue + private remote: TypedEventTarget + + constructor (init: MockStreamInit) { + const id = `${streamId++}` + + super({ + ...init, + id, + log: defaultLogger().forComponent(`libp2p:stream-pair:${init.direction}:${id}`) + }) + + this.local = init.local + this.remote = init.remote + + this.local.addEventListener('drain', () => { + this.safeDispatchEvent('drain') + }) + + this.remote.addEventListener('message', (evt) => { + if (this.status !== 'open') { + return + } + + this.onData(evt.data) + }) + this.remote.addEventListener('reset', (evt) => { + if (this.status !== 'open') { + return + } + + this.onRemoteReset() + }) + this.remote.addEventListener('closeWrite', (evt) => { + if (this.status !== 'open') { + return + } + + this.onRemoteCloseWrite() + }) + } + + sendData (data: Uint8ArrayList): SendResult { + const canSendMore = this.local.send(new StreamMessageEvent(data)) + + return { + sentBytes: data.byteLength, + canSendMore + } + } + + sendReset (): void { + this.local.send(new Event('reset')) + } + + async sendCloseWrite (options?: AbortOptions): Promise { + console.info('closing with', this.local.size(), 'items in queue') + + return raceSignal(new Promise((resolve, reject) => { + this.local.send(new Event('closeWrite')) + this.local.onIdle().then(resolve, reject) + }), options?.signal) + } + + async sendCloseRead (options?: AbortOptions): Promise { + return raceSignal(new Promise((resolve, reject) => { + this.local.send(new Event('closeRead')) + this.local.onIdle().then(resolve, reject) + }), options?.signal) + } + + sendPause (): void { + this.local.send(new Event('pause')) + } + + sendResume (): void { + this.local.send(new Event('resume')) + } + + onRemotePaused (): void { + this.local.pause() + } + + onRemoteResumed (): void { + this.local.resume() + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/moving-average.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/moving-average.ts new file mode 100644 index 000000000..9bbefaca3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/moving-average.ts @@ -0,0 +1,45 @@ +/** + * Implements exponential moving average. Ported from `moving-average`. + * + * @see https://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average + * @see https://www.npmjs.com/package/moving-average + */ +export class MovingAverage { + public movingAverage: number + public variance: number + public deviation: number + public forecast: number + private readonly timeSpan: number + private previousTime?: number + + constructor (timeSpan: number) { + this.timeSpan = timeSpan + this.movingAverage = 0 + this.variance = 0 + this.deviation = 0 + this.forecast = 0 + } + + alpha (t: number, pt: number): number { + return 1 - (Math.exp(-(t - pt) / this.timeSpan)) + } + + push (value: number, time: number = Date.now()): void { + if (this.previousTime != null) { + // calculate moving average + const a = this.alpha(time, this.previousTime) + const diff = value - this.movingAverage + const incr = a * diff + this.movingAverage = a * value + (1 - a) * this.movingAverage + // calculate variance & deviation + this.variance = (1 - a) * (this.variance + diff * incr) + this.deviation = Math.sqrt(this.variance) + // calculate forecast + this.forecast = this.movingAverage + a * diff + } else { + this.movingAverage = value + } + + this.previousTime = time + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr-connection-pair.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr-connection-pair.ts new file mode 100644 index 000000000..7f8104a71 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr-connection-pair.ts @@ -0,0 +1,146 @@ +import { StreamMessageEvent } from '@libp2p/interface' +import { defaultLogger } from '@libp2p/logger' +import { multiaddr } from '@multiformats/multiaddr' +import { raceSignal } from 'race-signal' +import { AbstractMultiaddrConnection } from './abstract-multiaddr-connection.ts' +import { MessageQueue } from './message-queue.ts' +import type { SendResult } from './abstract-message-stream.ts' +import type { MessageQueueInit } from './message-queue.ts' +import type { AbortOptions, Logger, MultiaddrConnection, MessageStreamDirection, TypedEventTarget } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Uint8ArrayList } from 'uint8arraylist' + +interface MockMulitaddrConnectionMessages { + message: MessageEvent + reset: Event + close: Event + pause: Event + resume: Event +} + +interface MockMulitaddrConnectionInit { + id: string, + log: Logger, + direction: MessageStreamDirection + local: MessageQueue + remote: TypedEventTarget + remoteAddr?: Multiaddr +} + +let multiaddrConnectionId = 0 + +class MockMultiaddrConnection extends AbstractMultiaddrConnection { + private local: MessageQueue + private remote: TypedEventTarget + + constructor (init: MockMulitaddrConnectionInit) { + super({ + ...init, + remoteAddr: init.remoteAddr ?? multiaddr(`/ip4/127.0.0.1/tcp/${init.id}`) + }) + + this.local = init.local + this.remote = init.remote + + this.local.addEventListener('drain', () => { + this.safeDispatchEvent('drain') + }) + + this.remote.addEventListener('message', (evt) => { + if (this.status !== 'open') { + return + } + + this.onData(evt.data) + }) + this.remote.addEventListener('reset', (evt) => { + if (this.status !== 'open') { + return + } + + this.onRemoteReset() + }) + this.remote.addEventListener('close', (evt) => { + this.onRemoteCloseWrite() + }) + this.remote.addEventListener('pause', (evt) => { + this.local.pause() + }) + this.remote.addEventListener('resume', (evt) => { + this.local.resume() + }) + } + + sendData (data: Uint8ArrayList): SendResult { + const canSendMore = this.local.send(new StreamMessageEvent(data)) + + return { + sentBytes: data.byteLength, + canSendMore + } + } + + sendReset (): void { + this.local.send(new Event('reset')) + } + + async sendCloseWrite (options?: AbortOptions): Promise { + return raceSignal(new Promise((resolve, reject) => { + this.local.send(new Event('close')) + this.local.onIdle().then(resolve, reject) + }), options?.signal) + } + + async sendCloseRead (options?: AbortOptions): Promise { + options?.signal?.throwIfAborted() + } + + sendPause (): void { + this.local.send(new Event('pause')) + } + + sendResume (): void { + this.local.send(new Event('resume')) + } +} + +export interface MultiaddrConnectionPairOptions extends MessageQueueInit { + outboundRemoteAddr?: Multiaddr + inboundRemoteAddr?: Multiaddr +} + +export function multiaddrConnectionPair (opts: MultiaddrConnectionPairOptions = {}): [MultiaddrConnection, MultiaddrConnection] { + const inboundId = `${multiaddrConnectionId++}` + const outboundId = `${multiaddrConnectionId++}` + + const outboundLog = defaultLogger().forComponent(`libp2p:mock-maconn:outbound:${inboundId}`) + const inboundLog = defaultLogger().forComponent(`libp2p:mock-maconn:inbound:${outboundId}`) + + const targetA = new MessageQueue({ + ...opts, + log: outboundLog + }) + const targetB = new MessageQueue({ + ...opts, + log: inboundLog + }) + + return [ + new MockMultiaddrConnection({ + id: inboundId, + direction: 'outbound', + local: targetA, + remote: targetB, + remoteAddr: opts?.outboundRemoteAddr, + log: outboundLog + }), + new MockMultiaddrConnection({ + id: outboundId, + direction: 'inbound', + local: targetB, + remote: targetA, + remoteAddr: opts?.inboundRemoteAddr, + log: inboundLog + }) + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/index.ts new file mode 100644 index 000000000..9ceb5c8d0 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/index.ts @@ -0,0 +1,6 @@ +export * from './is-global-unicast.js' +export * from './is-ip-based.js' +export * from './is-link-local.js' +export * from './is-loopback.js' +export * from './is-network-address.js' +export * from './is-private.js' diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-global-unicast.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-global-unicast.ts new file mode 100644 index 000000000..6844e3c61 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-global-unicast.ts @@ -0,0 +1,24 @@ +import { cidrContains } from '@chainsafe/netmask' +import { CODE_IP6 } from '@multiformats/multiaddr' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * Check if a given multiaddr is an IPv6 global unicast address + */ +export function isGlobalUnicast (ma: Multiaddr): boolean { + try { + for (const { code, value } of ma.getComponents()) { + if (value == null) { + continue + } + + if (code === CODE_IP6) { + return cidrContains('2000::/3', value) + } + } + } catch { + + } + + return false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-ip-based.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-ip-based.ts new file mode 100644 index 000000000..b7477172c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-ip-based.ts @@ -0,0 +1,21 @@ +import { CODE_IP4, CODE_IP6, CODE_IP6ZONE } from '@multiformats/multiaddr' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * Check if a given multiaddr is IP-based + */ +export function isIpBased (ma: Multiaddr): boolean { + try { + for (const { code } of ma.getComponents()) { + if (code === CODE_IP6ZONE) { + continue + } + + return code === CODE_IP4 || code === CODE_IP6 + } + } catch { + + } + + return false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-link-local.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-link-local.ts new file mode 100644 index 000000000..a4f38e209 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-link-local.ts @@ -0,0 +1,31 @@ +import { CODE_IP4, CODE_IP6, CODE_IP6ZONE } from '@multiformats/multiaddr' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * Check if a given multiaddr is a link-local address + */ +export function isLinkLocal (ma: Multiaddr): boolean { + try { + for (const { code, value } of ma.getComponents()) { + if (code === CODE_IP6ZONE) { + continue + } + + if (value == null) { + continue + } + + if (code === CODE_IP4) { + return value.startsWith('169.254.') + } + + if (code === CODE_IP6) { + return value.toLowerCase().startsWith('fe80') + } + } + } catch { + + } + + return false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-loopback.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-loopback.ts new file mode 100644 index 000000000..42fd58b20 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-loopback.ts @@ -0,0 +1,17 @@ +import { isLoopbackAddr } from 'is-loopback-addr' +import { isIpBased } from './is-ip-based.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * Check if a given multiaddr is a loopback address. + */ +export function isLoopback (ma: Multiaddr): boolean { + if (!isIpBased(ma)) { + // not an IP based multiaddr, cannot be private + return false + } + + const { address } = ma.nodeAddress() + + return isLoopbackAddr(address) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-network-address.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-network-address.ts new file mode 100644 index 000000000..358a1151b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-network-address.ts @@ -0,0 +1,30 @@ +import { CODE_IP4, CODE_IP6, CODE_IP6ZONE, CODE_DNS, CODE_DNS4, CODE_DNS6, CODE_DNSADDR } from '@multiformats/multiaddr' +import type { Multiaddr } from '@multiformats/multiaddr' + +const NETWORK_CODECS = [ + CODE_IP4, + CODE_IP6, + CODE_DNS, + CODE_DNS4, + CODE_DNS6, + CODE_DNSADDR +] + +/** + * Check if a given multiaddr is a network address + */ +export function isNetworkAddress (ma: Multiaddr): boolean { + try { + for (const { code } of ma.getComponents()) { + if (code === CODE_IP6ZONE) { + continue + } + + return NETWORK_CODECS.includes(code) + } + } catch { + + } + + return false +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-private.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-private.ts new file mode 100644 index 000000000..c5b30e7cb --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/multiaddr/is-private.ts @@ -0,0 +1,27 @@ +import { isPrivateIp } from '../private-ip.js' +import { isIpBased } from './is-ip-based.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * Check if a given multiaddr starts with a private address + */ +export function isPrivate (ma: Multiaddr): boolean { + try { + if (!isIpBased(ma)) { + // not an IP based multiaddr, cannot be private + return false + } + + const [[, value]] = ma.stringTuples() + + if (value == null) { + return false + } + + return isPrivateIp(value) ?? false + } catch { + + } + + return true +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/peer-queue.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/peer-queue.ts new file mode 100644 index 000000000..3a0574f4e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/peer-queue.ts @@ -0,0 +1,22 @@ +import { Queue } from './queue/index.js' +import type { Job } from './queue/job.js' +import type { AbortOptions, PeerId } from '@libp2p/interface' + +export interface PeerQueueJobOptions extends AbortOptions { + peerId: PeerId +} + +/** + * Extends Queue to add support for querying queued jobs by peer id + */ +export class PeerQueue extends Queue { + has (peerId: PeerId): boolean { + return this.find(peerId) != null + } + + find (peerId: PeerId): Job | undefined { + return this.queue.find(job => { + return peerId.equals(job.options.peerId) + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/priority-queue.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/priority-queue.ts new file mode 100644 index 000000000..20b1bc84f --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/priority-queue.ts @@ -0,0 +1,26 @@ +import { Queue } from './queue/index.js' +import type { QueueInit } from './queue/index.js' +import type { AbortOptions } from '@libp2p/interface' + +export interface PriorityQueueJobOptions extends AbortOptions { + priority: number +} + +export class PriorityQueue extends Queue { + constructor (init: QueueInit = {}) { + super({ + ...init, + sort: (a, b) => { + if (a.options.priority > b.options.priority) { + return -1 + } + + if (a.options.priority < b.options.priority) { + return 1 + } + + return 0 + } + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/private-ip.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/private-ip.ts new file mode 100644 index 000000000..8c1c2c0a3 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/private-ip.ts @@ -0,0 +1,107 @@ +import { isIPv4, isIPv6 } from '@chainsafe/is-ip' +import { Netmask } from 'netmask' + +const PRIVATE_IP_RANGES = [ + '0.0.0.0/8', + '10.0.0.0/8', + '100.64.0.0/10', + '127.0.0.0/8', + '169.254.0.0/16', + '172.16.0.0/12', + '192.0.0.0/24', + '192.0.0.0/29', + '192.0.0.8/32', + '192.0.0.9/32', + '192.0.0.10/32', + '192.0.0.170/32', + '192.0.0.171/32', + '192.0.2.0/24', + '192.31.196.0/24', + '192.52.193.0/24', + '192.88.99.0/24', + '192.168.0.0/16', + '192.175.48.0/24', + '198.18.0.0/15', + '198.51.100.0/24', + '203.0.113.0/24', + '240.0.0.0/4', + '255.255.255.255/32' +] + +const NETMASK_RANGES = PRIVATE_IP_RANGES.map(ipRange => new Netmask(ipRange)) + +function ipv4Check (ipAddr: string): boolean { + for (const r of NETMASK_RANGES) { + if (r.contains(ipAddr)) { return true } + } + + return false +} + +function isIpv4MappedIpv6 (ipAddr: string): boolean { + return /^::ffff:([0-9a-fA-F]{1,4}):([0-9a-fA-F]{1,4})$/.test(ipAddr) +} + +/** + * @see https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2 + */ +function ipv4MappedIpv6Check (ipAddr: string): boolean { + const parts = ipAddr.split(':') + + if (parts.length < 2) { + return false + } + + const octet34 = parts[parts.length - 1].padStart(4, '0') + const octet12 = parts[parts.length - 2].padStart(4, '0') + + const ip4 = `${parseInt(octet12.substring(0, 2), 16)}.${parseInt(octet12.substring(2), 16)}.${parseInt(octet34.substring(0, 2), 16)}.${parseInt(octet34.substring(2), 16)}` + + return ipv4Check(ip4) +} + +/** + * @see https://datatracker.ietf.org/doc/html/rfc4291#section-2.2 example 3 + */ +function isIpv4EmbeddedIpv6 (ipAddr: string): boolean { + return /^::ffff:([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.test(ipAddr) +} + +function ipv4EmbeddedIpv6Check (ipAddr: string): boolean { + const parts = ipAddr.split(':') + const ip4 = parts[parts.length - 1] + + return ipv4Check(ip4) +} + +function ipv6Check (ipAddr: string): boolean { + return /^::$/.test(ipAddr) || + /^::1$/.test(ipAddr) || + /^64:ff9b::([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})\.([0-9]{1,3})$/.test(ipAddr) || + /^100::([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4})$/.test(ipAddr) || + /^2001::([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4})$/.test(ipAddr) || + /^2001:2[0-9a-fA-F]:([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4})$/.test(ipAddr) || + /^2001:db8:([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4})$/.test(ipAddr) || + /^2002:([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4}):?([0-9a-fA-F]{0,4})$/.test(ipAddr) || + /^f[c-d]([0-9a-fA-F]{2,2}):/i.test(ipAddr) || + /^fe[8-9a-bA-B][0-9a-fA-F]:/i.test(ipAddr) || + /^ff([0-9a-fA-F]{2,2}):/i.test(ipAddr) +} + +export function isPrivateIp (ip: string): boolean | undefined { + if (isIPv4(ip)) { + return ipv4Check(ip) + } + + if (isIpv4MappedIpv6(ip)) { + return ipv4MappedIpv6Check(ip) + } + + if (isIpv4EmbeddedIpv6(ip)) { + return ipv4EmbeddedIpv6Check(ip) + } + + if (isIPv6(ip)) { + return ipv6Check(ip) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/index.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/index.ts new file mode 100644 index 000000000..67147a7d8 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/index.ts @@ -0,0 +1,450 @@ +import { AbortError } from '@libp2p/interface' +import { pushable } from 'it-pushable' +import { TypedEventEmitter } from 'main-event' +import { raceEvent } from 'race-event' +import { debounce } from '../debounce.js' +import { QueueFullError } from '../errors.js' +import { Job } from './job.js' +import type { AbortOptions, Metrics } from '@libp2p/interface' + +export type { Job, JobTimeline } from './job.js' +export type { JobRecipient } from './recipient.js' + +export interface Comparator { + (a: T, b: T): -1 | 0 | 1 +} + +export interface QueueInit { + /** + * Concurrency limit. + * + * Minimum: `1`. + * + * @default Infinity + */ + concurrency?: number + + /** + * If the queue size grows to larger than this number the promise returned + * from the add function will reject + * + * @default Infinity + */ + maxSize?: number + + /** + * The name of the metric for the queue length + */ + metricName?: string + + /** + * An implementation of the libp2p Metrics interface + */ + metrics?: Metrics + + /** + * An optional function that will sort the queue after a job has been added + */ + sort?: Comparator> +} + +export type JobStatus = 'queued' | 'running' | 'errored' | 'complete' + +export interface RunFunction { + (options: Options): Promise +} + +export interface JobMatcher { + (options?: Partial): boolean +} + +export interface QueueJobSuccess { + job: Job + result: JobReturnType +} + +export interface QueueJobFailure { + job: Job + error: Error +} + +export interface QueueEvents { + /** + * A job is about to start running + */ + active: CustomEvent + + /** + * All jobs have finished and the queue is empty + */ + idle: CustomEvent + + /** + * The queue is empty, jobs may be running + */ + empty: CustomEvent + + /** + * A job was added to the queue + */ + add: CustomEvent + + /** + * A job has finished or failed + */ + next: CustomEvent + + /** + * A job has finished successfully + */ + completed: CustomEvent + + /** + * A job has failed + * + * @deprecated Listen for the 'failure' event instead - it gives more context and is generally more useful, this event will be removed in a future release + */ + error: CustomEvent + + /** + * Emitted just after `"completed", a job has finished successfully - this + * event gives access to the job and it's result + */ + success: CustomEvent> + + /** + * Emitted just after `"error", a job has failed - this event gives access to + * the job and the thrown error + */ + failure: CustomEvent> +} + +/** + * Heavily influence by `p-queue` with the following differences: + * + * 1. Items remain at the head of the queue while they are running so `queue.size` includes `queue.pending` items - this is so interested parties can join the results of a queue item while it is running + * 2. The options for a job are stored separately to the job in order for them to be modified while they are still in the queue + */ +export class Queue extends TypedEventEmitter> { + public concurrency: number + public maxSize: number + public queue: Array> + private pending: number + private readonly sort?: Comparator> + private paused: boolean + + constructor (init: QueueInit = {}) { + super() + + this.concurrency = init.concurrency ?? Number.POSITIVE_INFINITY + this.maxSize = init.maxSize ?? Number.POSITIVE_INFINITY + this.pending = 0 + this.paused = false + + if (init.metricName != null) { + init.metrics?.registerMetricGroup(init.metricName, { + calculate: () => { + return { + size: this.queue.length, + running: this.pending, + queued: this.queue.length - this.pending + } + } + }) + } + + this.sort = init.sort + this.queue = [] + + this.emitEmpty = debounce(this.emitEmpty.bind(this), 1) + this.emitIdle = debounce(this.emitIdle.bind(this), 1) + } + + emitEmpty (): void { + if (this.size !== 0) { + return + } + + this.safeDispatchEvent('empty') + } + + emitIdle (): void { + if (this.running !== 0) { + return + } + + this.safeDispatchEvent('idle') + } + + pause (): void { + this.paused = true + } + + resume (): void { + if (!this.paused) { + return + } + + this.paused = false + this.tryToStartAnother() + } + + private tryToStartAnother (): boolean { + if (this.paused) { + return false + } + + if (this.size === 0) { + this.emitEmpty() + + if (this.running === 0) { + this.emitIdle() + } + + return false + } + + if (this.pending < this.concurrency) { + let job: Job | undefined + + for (const j of this.queue) { + if (j.status === 'queued') { + job = j + break + } + } + + if (job == null) { + return false + } + + this.safeDispatchEvent('active') + + this.pending++ + + void job.run() + .finally(() => { + // remove the job from the queue + for (let i = 0; i < this.queue.length; i++) { + if (this.queue[i] === job) { + this.queue.splice(i, 1) + break + } + } + + this.pending-- + this.tryToStartAnother() + this.safeDispatchEvent('next') + }) + + return true + } + + return false + } + + private enqueue (job: Job): void { + this.queue.push(job) + + if (this.sort != null) { + this.queue.sort(this.sort) + } + } + + /** + * Adds a sync or async task to the queue. Always returns a promise. + */ + async add (fn: RunFunction, options?: JobOptions): Promise { + options?.signal?.throwIfAborted() + + if (this.size === this.maxSize) { + throw new QueueFullError() + } + + const job = new Job(fn, options) + this.enqueue(job) + this.safeDispatchEvent('add') + this.tryToStartAnother() + + return job.join(options) + .then(result => { + this.safeDispatchEvent('completed', { detail: result }) + this.safeDispatchEvent('success', { detail: { job, result } }) + + return result + }) + .catch(err => { + if (job.status === 'queued') { + // job was aborted before it started - remove the job from the queue + for (let i = 0; i < this.queue.length; i++) { + if (this.queue[i] === job) { + this.queue.splice(i, 1) + break + } + } + } + + this.safeDispatchEvent('failure', { detail: { job, error: err } }) + + throw err + }) + } + + /** + * Clear the queue + */ + clear (): void { + this.queue.splice(0, this.queue.length) + } + + /** + * Abort all jobs in the queue and clear it + */ + abort (): void { + this.queue.forEach(job => { + job.abort(new AbortError()) + }) + + this.clear() + } + + /** + * Can be called multiple times. Useful if you for example add additional items at a later time. + * + * @returns A promise that settles when the queue becomes empty. + */ + async onEmpty (options?: AbortOptions): Promise { + // Instantly resolve if the queue is empty + if (this.size === 0) { + return + } + + await raceEvent(this, 'empty', options?.signal) + } + + /** + * @returns A promise that settles when the queue size is less than the given + * limit: `queue.size < limit`. + * + * If you want to avoid having the queue grow beyond a certain size you can + * `await queue.onSizeLessThan()` before adding a new item. + * + * Note that this only limits the number of items waiting to start. There + * could still be up to `concurrency` jobs already running that this call does + * not include in its calculation. + */ + async onSizeLessThan (limit: number, options?: AbortOptions): Promise { + // Instantly resolve if the queue is empty. + if (this.size < limit) { + return + } + + await raceEvent(this, 'next', options?.signal, { + filter: () => this.size < limit + }) + } + + /** + * The difference with `.onEmpty` is that `.onIdle` guarantees that all work + * from the queue has finished. `.onEmpty` merely signals that the queue is + * empty, but it could mean that some promises haven't completed yet. + * + * @returns A promise that settles when the queue becomes empty, and all + * promises have completed; `queue.size === 0 && queue.pending === 0`. + */ + async onIdle (options?: AbortOptions): Promise { + // Instantly resolve if none pending and if nothing else is queued + if (this.pending === 0 && this.size === 0) { + return + } + + await raceEvent(this, 'idle', options?.signal) + } + + /** + * Size of the queue including running items + */ + get size (): number { + return this.queue.length + } + + /** + * The number of queued items waiting to run. + */ + get queued (): number { + return this.queue.length - this.pending + } + + /** + * The number of items currently running. + */ + get running (): number { + return this.pending + } + + /** + * Returns an async generator that makes it easy to iterate over the results + * of jobs added to the queue. + * + * The generator will end when the queue becomes idle, that is there are no + * jobs running and no jobs that have yet to run. + * + * If you need to keep the queue open indefinitely, consider using it-pushable + * instead. + */ + async * toGenerator (options?: AbortOptions): AsyncGenerator { + options?.signal?.throwIfAborted() + + const stream = pushable({ + objectMode: true + }) + + const cleanup = (err?: Error): void => { + if (err != null) { + this.abort() + } else { + this.clear() + } + + stream.end(err) + } + + const onQueueJobComplete = (evt: CustomEvent): void => { + if (evt.detail != null) { + stream.push(evt.detail) + } + } + + const onQueueFailure = (evt: CustomEvent>): void => { + cleanup(evt.detail.error) + } + + const onQueueIdle = (): void => { + cleanup() + } + + // clear the queue and throw if the query is aborted + const onSignalAbort = (): void => { + cleanup(new AbortError('Queue aborted')) + } + + // add listeners + this.addEventListener('completed', onQueueJobComplete) + this.addEventListener('failure', onQueueFailure) + this.addEventListener('idle', onQueueIdle) + options?.signal?.addEventListener('abort', onSignalAbort) + + try { + yield * stream + } finally { + // remove listeners + this.removeEventListener('completed', onQueueJobComplete) + this.removeEventListener('failure', onQueueFailure) + this.removeEventListener('idle', onQueueIdle) + options?.signal?.removeEventListener('abort', onSignalAbort) + + // empty the queue for when the user has broken out of a loop early + cleanup() + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/job.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/job.ts new file mode 100644 index 000000000..df4bbb77e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/job.ts @@ -0,0 +1,106 @@ +import { AbortError } from '@libp2p/interface' +import { setMaxListeners } from 'main-event' +import { raceSignal } from 'race-signal' +import { JobRecipient } from './recipient.js' +import type { JobStatus } from './index.js' +import type { AbortOptions } from '@libp2p/interface' + +/** + * Returns a random string + */ +function randomId (): string { + return `${(parseInt(String(Math.random() * 1e9), 10)).toString()}${Date.now()}` +} + +export interface JobTimeline { + created: number + started?: number + finished?: number +} + +export class Job { + public id: string + public fn: (options: JobOptions) => Promise + public options: JobOptions + public recipients: Array> + public status: JobStatus + public readonly timeline: JobTimeline + private readonly controller: AbortController + + constructor (fn: (options: JobOptions) => Promise, options: any) { + this.id = randomId() + this.status = 'queued' + this.fn = fn + this.options = options + this.recipients = [] + this.timeline = { + created: Date.now() + } + + this.controller = new AbortController() + setMaxListeners(Infinity, this.controller.signal) + + this.onAbort = this.onAbort.bind(this) + } + + abort (err: Error): void { + this.controller.abort(err) + } + + onAbort (): void { + const allAborted = this.recipients.reduce((acc, curr) => { + return acc && (curr.signal?.aborted === true) + }, true) + + // if all recipients have aborted the job, actually abort the job + if (allAborted) { + this.controller.abort(new AbortError()) + this.cleanup() + } + } + + async join (options: AbortOptions = {}): Promise { + const recipient = new JobRecipient(options.signal) + this.recipients.push(recipient) + + options.signal?.addEventListener('abort', this.onAbort) + + return recipient.deferred.promise + } + + async run (): Promise { + this.status = 'running' + this.timeline.started = Date.now() + + try { + this.controller.signal.throwIfAborted() + + const result = await raceSignal(this.fn({ + ...(this.options ?? {}), + signal: this.controller.signal + }), this.controller.signal) + + this.recipients.forEach(recipient => { + recipient.deferred.resolve(result) + }) + + this.status = 'complete' + } catch (err) { + this.recipients.forEach(recipient => { + recipient.deferred.reject(err) + }) + + this.status = 'errored' + } finally { + this.timeline.finished = Date.now() + this.cleanup() + } + } + + cleanup (): void { + this.recipients.forEach(recipient => { + recipient.cleanup() + recipient.signal?.removeEventListener('abort', this.onAbort) + }) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/recipient.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/recipient.ts new file mode 100644 index 000000000..f482651ef --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/queue/recipient.ts @@ -0,0 +1,24 @@ +import { AbortError } from '@libp2p/interface' +import pDefer from 'p-defer' +import type { DeferredPromise } from 'p-defer' + +export class JobRecipient { + public deferred: DeferredPromise + public signal?: AbortSignal + + constructor (signal?: AbortSignal) { + this.signal = signal + this.deferred = pDefer() + + this.onAbort = this.onAbort.bind(this) + this.signal?.addEventListener('abort', this.onAbort) + } + + onAbort (): void { + this.deferred.reject(this.signal?.reason ?? new AbortError()) + } + + cleanup (): void { + this.signal?.removeEventListener('abort', this.onAbort) + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/rate-limiter.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/rate-limiter.ts new file mode 100644 index 000000000..1cb64221c --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/rate-limiter.ts @@ -0,0 +1,260 @@ +import { RateLimitError } from './errors.js' + +export interface RateLimiterInit { + /** + * Number of points + * + * @default 4 + */ + points?: number + + /** + * Per seconds + * + * @default 1 + */ + duration?: number + + /** + * Block if consumed more than points in current duration for blockDuration seconds + * + * @default 0 + */ + blockDuration?: number + + /** + * @default "rlflx" + */ + keyPrefix?: string +} + +export interface GetKeySecDurationOptions { + customDuration?: number +} + +export interface RateLimiterResult { + remainingPoints: number + msBeforeNext: number + consumedPoints: number + isFirstInDuration: boolean +} + +export interface RateRecord { + value: number + expiresAt?: Date + timeoutId?: ReturnType +} + +export class RateLimiter { + public readonly memoryStorage: MemoryStorage + protected points: number + protected duration: number + protected blockDuration: number + protected keyPrefix: string + + constructor (opts: RateLimiterInit = {}) { + this.points = opts.points ?? 4 + this.duration = opts.duration ?? 1 + this.blockDuration = opts.blockDuration ?? 0 + this.keyPrefix = opts.keyPrefix ?? 'rlflx' + this.memoryStorage = new MemoryStorage() + } + + consume (key: string, pointsToConsume: number = 1, options: GetKeySecDurationOptions = {}): RateLimiterResult { + const rlKey = this.getKey(key) + const secDuration = this._getKeySecDuration(options) + let res = this.memoryStorage.incrby(rlKey, pointsToConsume, secDuration) + res.remainingPoints = Math.max(this.points - res.consumedPoints, 0) + + if (res.consumedPoints > this.points) { + // Block only first time when consumed more than points + if (this.blockDuration > 0 && res.consumedPoints <= (this.points + pointsToConsume)) { + // Block key + res = this.memoryStorage.set(rlKey, res.consumedPoints, this.blockDuration) + } + + throw new RateLimitError('Rate limit exceeded', res) + } + + return res + } + + penalty (key: string, points: number = 1, options: GetKeySecDurationOptions = {}): RateLimiterResult { + const rlKey = this.getKey(key) + const secDuration = this._getKeySecDuration(options) + const res = this.memoryStorage.incrby(rlKey, points, secDuration) + res.remainingPoints = Math.max(this.points - res.consumedPoints, 0) + + return res + } + + reward (key: string, points: number = 1, options: GetKeySecDurationOptions = {}): RateLimiterResult { + const rlKey = this.getKey(key) + const secDuration = this._getKeySecDuration(options) + const res = this.memoryStorage.incrby(rlKey, -points, secDuration) + res.remainingPoints = Math.max(this.points - res.consumedPoints, 0) + + return res + } + + /** + * Block any key for secDuration seconds + * + * @param key + * @param secDuration + */ + block (key: string, secDuration: number): RateLimiterResult { + const msDuration = secDuration * 1000 + const initPoints = this.points + 1 + + this.memoryStorage.set(this.getKey(key), initPoints, secDuration) + + return { + remainingPoints: 0, + msBeforeNext: msDuration === 0 ? -1 : msDuration, + consumedPoints: initPoints, + isFirstInDuration: false + } + } + + set (key: string, points: number, secDuration: number = 0): RateLimiterResult { + const msDuration = (secDuration >= 0 ? secDuration : this.duration) * 1000 + + this.memoryStorage.set(this.getKey(key), points, secDuration) + + return { + remainingPoints: 0, + msBeforeNext: msDuration === 0 ? -1 : msDuration, + consumedPoints: points, + isFirstInDuration: false + } + } + + get (key: string): RateLimiterResult | undefined { + const res = this.memoryStorage.get(this.getKey(key)) + + if (res != null) { + res.remainingPoints = Math.max(this.points - res.consumedPoints, 0) + } + + return res + } + + delete (key: string): void { + this.memoryStorage.delete(this.getKey(key)) + } + + private _getKeySecDuration (options?: GetKeySecDurationOptions): number { + if (options?.customDuration != null && options.customDuration >= 0) { + return options.customDuration + } + + return this.duration + } + + getKey (key: string): string { + return this.keyPrefix.length > 0 ? `${this.keyPrefix}:${key}` : key + } + + parseKey (rlKey: string): string { + return rlKey.substring(this.keyPrefix.length) + } +} + +export class MemoryStorage { + public readonly storage: Map + + constructor () { + this.storage = new Map() + } + + incrby (key: string, value: number, durationSec: number): RateLimiterResult { + const existing = this.storage.get(key) + + if (existing != null) { + const msBeforeExpires = existing.expiresAt != null + ? existing.expiresAt.getTime() - new Date().getTime() + : -1 + + if (existing.expiresAt == null || msBeforeExpires > 0) { + // Change value + existing.value += value + + return { + remainingPoints: 0, + msBeforeNext: msBeforeExpires, + consumedPoints: existing.value, + isFirstInDuration: false + } + } + + return this.set(key, value, durationSec) + } + + return this.set(key, value, durationSec) + } + + set (key: string, value: number, durationSec: number): RateLimiterResult { + const durationMs = durationSec * 1000 + const existing = this.storage.get(key) + + if (existing != null) { + clearTimeout(existing.timeoutId) + } + + const record: RateRecord = { + value, + expiresAt: durationMs > 0 ? new Date(Date.now() + durationMs) : undefined + } + + this.storage.set(key, record) + + if (durationMs > 0) { + record.timeoutId = setTimeout(() => { + this.storage.delete(key) + }, durationMs) + + if ((record.timeoutId as any).unref != null) { + (record.timeoutId as any).unref() + } + } + + return { + remainingPoints: 0, + msBeforeNext: durationMs === 0 ? -1 : durationMs, + consumedPoints: record.value, + isFirstInDuration: true + } + } + + get (key: string): RateLimiterResult | undefined { + const existing = this.storage.get(key) + + if (existing != null) { + const msBeforeExpires = existing.expiresAt != null + ? existing.expiresAt.getTime() - new Date().getTime() + : -1 + return { + remainingPoints: 0, + msBeforeNext: msBeforeExpires, + consumedPoints: existing.value, + isFirstInDuration: false + } + } + } + + delete (key: string): boolean { + const record = this.storage.get(key) + + if (record != null) { + if (record.timeoutId != null) { + clearTimeout(record.timeoutId) + } + + this.storage.delete(key) + + return true + } + return false + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/repeating-task.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/repeating-task.ts new file mode 100644 index 000000000..0393c2c11 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/repeating-task.ts @@ -0,0 +1,162 @@ +import { anySignal } from 'any-signal' +import { setMaxListeners } from 'main-event' +import { debounce } from './debounce.ts' +import type { AbortOptions } from '@libp2p/interface' + +export interface RepeatingTask { + /** + * Update the interval after which the next iteration of the task will run. + * + * This is useful if, for example, you want to retry a task with a short rest + * duration until it succeeds, then periodically after that. + * + * This only affects the next iteration of the task, if it is currently + * running, that run will not be interrupted. + * + * Setting the interval to the current value has no effect. + */ + setInterval(ms: number): void + + /** + * Update the amount of time a task will run before the passed abort signal + * will fire. + * + * This only affects the next iteration of the task, if it is currently + * running, that run will not be interrupted. + */ + setTimeout(ms: number): void + + /** + * Schedule the task to be run immediately - if the task is not running it + * will run after a short delay in order to debounce multiple `.run()` + * invocations. + */ + run(): void + + /** + * Start the task running + */ + start(): void + + /** + * Stop the task running + */ + stop(): void +} + +export interface RepeatingTaskOptions { + /** + * How long the task is allowed to run before the passed AbortSignal fires an + * abort event + */ + timeout?: number + + /** + * Whether to schedule the task to run immediately + * + * @default false + */ + runImmediately?: boolean + + /** + * When `.run()` is called to run the task outside of the current interval, + * debounce repeated calls to `.run()` by this amount. + * + * @default 100 + */ + debounce?: number +} + +export function repeatingTask (fn: (options?: AbortOptions) => void | Promise, interval: number, options?: RepeatingTaskOptions): RepeatingTask { + let timeout: ReturnType + let shutdownController: AbortController + let running = false + + function runTask (): void { + const opts: AbortOptions = { + signal: shutdownController.signal + } + + if (options?.timeout != null) { + const signal = anySignal([shutdownController.signal, AbortSignal.timeout(options.timeout)]) + setMaxListeners(Infinity, signal) + + opts.signal = signal + } + + running = true + + Promise.resolve().then(async () => { + await fn(opts) + }) + .catch(() => {}) + .finally(() => { + running = false + + if (shutdownController.signal.aborted) { + // task has been cancelled, bail + return + } + + // reschedule + timeout = setTimeout(runTask, interval) + }) + } + + const runTaskDebounced = debounce(runTask, options?.debounce ?? 100) + + let started = false + + return { + setInterval: (ms): void => { + if (interval === ms) { + // already running at this interval, nothing to do + return + } + + interval = ms + + // maybe reschedule + if (timeout != null) { + clearTimeout(timeout) + timeout = setTimeout(runTask, interval) + } + }, + setTimeout: (ms): void => { + options ??= {} + options.timeout = ms + }, + run: (): void => { + if (running) { + return + } + + clearTimeout(timeout) + runTaskDebounced() + }, + start: (): void => { + if (started) { + return + } + + started = true + shutdownController = new AbortController() + setMaxListeners(Infinity, shutdownController.signal) + + // run now + if (options?.runImmediately === true) { + queueMicrotask(() => { + runTask() + }) + } else { + // run later + timeout = setTimeout(runTask, interval) + } + }, + stop: (): void => { + clearTimeout(timeout) + shutdownController?.abort() + started = false + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/socket-writer.browser.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/socket-writer.browser.ts new file mode 100644 index 000000000..494c7f6a7 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/socket-writer.browser.ts @@ -0,0 +1,3 @@ +export function socketWriter (): void { + throw new Error('Unsupported in browsers') +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/socket-writer.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/socket-writer.ts new file mode 100644 index 000000000..0dda552de --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/socket-writer.ts @@ -0,0 +1,61 @@ +import stream from 'node:stream' +import { Uint8ArrayList } from 'uint8arraylist' + +export interface SocketWriter { + /** + * Write any available data into the socket, if the socket's internal write + * buffer has available capacity + */ + pull (): boolean + + /** + * Write data into the socket, returns false if the socket's internal write + * buffer is at capacity + */ + write (data: Uint8Array | Uint8Array[] | Uint8ArrayList): boolean +} + +export function socketWriter (socket: stream.Duplex): SocketWriter { + const queue = new Uint8ArrayList() + + return { + pull (): boolean { + if (socket.writableNeedDrain) { + return false + } + + for (const buf of queue) { + queue.consume(buf.byteLength) + + if (!socket.write(buf)) { + // continue writing after drain event. this is a synchronous operation + // so it will not interleave with the `this.writeToSocket()` invocation + // in this.sendData so all data will be sent in-order + if (queue.byteLength > 0) { + socket.once('drain', () => { + this.pull() + }) + } + + return false + } + } + + return true + }, + + write (data: Uint8Array | Uint8Array[] | Uint8ArrayList): boolean { + if (Array.isArray(data)) { + queue.appendAll(data) + } else { + queue.append(data) + } + + if (socket.writableNeedDrain) { + return false + } + + return this.pull() + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/stream-pair.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/stream-pair.ts new file mode 100644 index 000000000..c56f1b43a --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/stream-pair.ts @@ -0,0 +1,61 @@ +import { raceEvent } from 'race-event' +import { mockMuxer } from './mock-muxer.ts' +import { multiaddrConnectionPair } from './multiaddr-connection-pair.ts' +import { echo } from './stream-utils.ts' +import type { Stream } from '@libp2p/interface' +import { Uint8ArrayList } from 'uint8arraylist' + +export interface StreamPairOptions { + /** + * How long to wait in ms before sending messages + * + * @default 1 + */ + delay?: number + + /** + * If more than this many messages are sent within delay, write backpressure + * will be applied + */ + capacity?: number + + /** + * Simulate having pre-negotiated a protocol by passing it here + */ + protocol?: string +} + +/** + * Returns two streams connected to each other with a slight delay in sending + * messages to simulate a network + */ +export async function streamPair (opts: StreamPairOptions = {}): Promise<[Stream, Stream]> { + const [outboundConnection, inboundConnection] = multiaddrConnectionPair(opts) + + const localMuxer = mockMuxer().createStreamMuxer(outboundConnection) + const remoteMuxer = mockMuxer().createStreamMuxer(inboundConnection) + + const [ + outboundStream, + inboundStream + ] = await Promise.all([ + localMuxer.createStream({ + protocol: opts.protocol + }), + raceEvent>(remoteMuxer, 'stream').then(evt => { + return evt.detail + }) + ]) + + return [ + outboundStream, + inboundStream + ] +} + +export async function echoStream (opts: StreamPairOptions = {}): Promise { + const [outbound, inbound] = await streamPair(opts) + echo(inbound) + + return outbound +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/stream-utils.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/stream-utils.ts new file mode 100644 index 000000000..393e7cb3e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/stream-utils.ts @@ -0,0 +1,807 @@ +import { StreamMessageEvent, StreamCloseEvent } from '@libp2p/interface' +import { pipe as itPipe } from 'it-pipe' +import { pushable } from 'it-pushable' +import { pEvent } from 'p-event' +import { raceEvent } from 'race-event' +import { raceSignal } from 'race-signal' +import * as varint from 'uint8-varint' +import { Uint8ArrayList } from 'uint8arraylist' +import { UnexpectedEOFError } from './errors.js' +import type { MessageStream } from '@libp2p/interface' +import type { AbortOptions } from '@multiformats/multiaddr' +import type { Duplex, Source, Transform, Sink } from 'it-stream-types' + +const DEFAULT_MAX_BUFFER_SIZE = 4_194_304 + +export class UnwrappedError extends Error { + static name = 'UnwrappedError' + name = 'UnwrappedError' +} + +/** + * The reported length of the next data message was not a positive integer + */ +export class InvalidMessageLengthError extends Error { + name = 'InvalidMessageLengthError' + code = 'ERR_INVALID_MSG_LENGTH' +} + +/** + * The reported length of the next data message was larger than the configured + * max allowable value + */ +export class InvalidDataLengthError extends Error { + name = 'InvalidDataLengthError' + code = 'ERR_MSG_DATA_TOO_LONG' +} + +/** + * The varint used to specify the length of the next data message contained more + * bytes than the configured max allowable value + */ +export class InvalidDataLengthLengthError extends Error { + name = 'InvalidDataLengthLengthError' + code = 'ERR_MSG_LENGTH_TOO_LONG' +} + +export interface ByteStreamOpts { + /** + * Incoming bytes are buffered until read, this setting limits how many bytes + * will be buffered. + * + * @default 4_194_304 + */ + maxBufferSize?: number + + /** + * If true, prevent message events propagating after they have been received, + * + * This is useful for when there are be other observers of messages and the + * caller does not wish to them to receive anything + */ + stopPropagation?: boolean +} + +export interface ReadBytesOptions extends AbortOptions { + /** + * If specified, read this number of bytes from the stream + */ + bytes: number +} + +export interface ByteStream { + /** + * Read bytes from the stream. + * + * If a required number of bytes is passed as an option, this will wait for + * the underlying stream to supply that number of bytes, throwing an + * `UnexpectedEOFError` if the stream closes before this happens. + * + * If no required number of bytes is passed, this will return `null` if the + * underlying stream closes before supplying any bytes. + */ + read(options: ReadBytesOptions): Promise + read(options?: AbortOptions): Promise + + /** + * Write the passed bytes to the stream + */ + write(data: Uint8Array | Uint8ArrayList, options?: AbortOptions): Promise + + /** + * After calling this method the bytestream can no longer be used. Any unread + * data will be emitted as a message event during the microtask queue of the + * current event loop tick. + */ + unwrap(): Stream +} + +export function byteStream (stream: Stream, opts?: ByteStreamOpts): ByteStream { + const maxBufferSize = opts?.maxBufferSize ?? DEFAULT_MAX_BUFFER_SIZE + const readBuffer = new Uint8ArrayList() + let hasBytes = Promise.withResolvers() + let unwrapped = false + + const onMessage = (evt: StreamMessageEvent): void => { + if (opts?.stopPropagation === true) { + evt.stopImmediatePropagation() + } + + readBuffer.append(evt.data) + + if (readBuffer.byteLength > maxBufferSize) { + const readBufferSize = readBuffer.byteLength + readBuffer.consume(readBuffer.byteLength) + hasBytes.reject(new Error(`Read buffer overflow - ${readBufferSize} > ${maxBufferSize}`)) + } + + hasBytes.resolve() + } + stream.addEventListener('message', onMessage) + + const onClose = (evt: StreamCloseEvent): void => { + if (evt.error != null) { + hasBytes.reject(evt.error) + } else { + hasBytes.resolve() + } + } + stream.addEventListener('close', onClose) + + const onRemoteCloseWrite = (): void => { + hasBytes.resolve() + } + stream.addEventListener('remoteCloseWrite', onRemoteCloseWrite) + + const byteStream: ByteStream = { + // @ts-expect-error options type prevents type inference + async read (options?: ReadBytesOptions) { + if (unwrapped === true) { + throw new UnwrappedError('Stream was unwrapped') + } + + if (stream.readStatus !== 'readable') { + if (options?.bytes == null) { + return null + } + + throw new UnexpectedEOFError('Unexpected EOF - stream was not readable') + } + + const bytesToRead = options?.bytes ?? 1 + + while (true) { + if (readBuffer.byteLength >= bytesToRead) { + // if we are about to exit the loop this promise will not be awaited + // so resolve it to prevent and unhandled promise rejections that may + // occur + hasBytes.resolve() + + break + } + + await raceSignal(hasBytes.promise, options?.signal) + + if (stream.readStatus !== 'readable') { + if (readBuffer.byteLength === 0 && options?.bytes == null) { + return null + } + + break + } + + hasBytes = Promise.withResolvers() + } + + const toRead = options?.bytes ?? readBuffer.byteLength + + if (readBuffer.byteLength < toRead) { + if (stream.readStatus !== 'readable') { + throw new UnexpectedEOFError(`Unexpected EOF - stream status was "${stream.readStatus}" and not "readable"`) + } + + return byteStream.read(options) + } + + const output = readBuffer.sublist(0, toRead) + readBuffer.consume(toRead) + + return output + }, + async write (data: Uint8Array | Uint8ArrayList, options?: AbortOptions) { + if (unwrapped === true) { + throw new UnwrappedError('Stream was unwrapped') + } + + const sendMore = stream.send(data) + + if (sendMore === false) { + await raceEvent(stream, 'drain', options?.signal) + } + }, + unwrap () { + // already unwrapped, just return the original stream + if (unwrapped) { + return stream + } + + // only unwrap once + unwrapped = true + stream.removeEventListener('message', onMessage) + stream.removeEventListener('close', onClose) + stream.removeEventListener('remoteCloseWrite', onRemoteCloseWrite) + + // emit any unread data + if (readBuffer.byteLength > 0) { + stream.push(readBuffer) + } + + return stream + } + } + + return byteStream +} + +export interface LengthPrefixedStream { + /** + * Read the next length-prefixed number of bytes from the stream + */ + read(options?: AbortOptions): Promise + + /** + * Write the passed bytes to the stream prefixed by their length + */ + write(data: Uint8Array | Uint8ArrayList, options?: AbortOptions): Promise + + /** + * Write passed list of bytes, prefix by their individual lengths to the stream as a single write + */ + writeV(input: Array, options?: AbortOptions): Promise + + /** + * Returns the underlying stream + */ + unwrap(): Stream +} + +export interface LengthPrefixedStreamOpts extends ByteStreamOpts { + lengthEncoder (value: number): Uint8ArrayList | Uint8Array + lengthDecoder (data: Uint8ArrayList): number + maxLengthLength: number + maxDataLength: number +} + +export function lpStream (stream: Stream, opts: Partial = {}): LengthPrefixedStream { + const bytes = byteStream(stream, opts) + + if (opts.maxDataLength != null && opts.maxLengthLength == null) { + // if max data length is set but max length length is not, calculate the + // max length length needed to encode max data length + opts.maxLengthLength = varint.encodingLength(opts.maxDataLength) + } + + const decodeLength = opts?.lengthDecoder ?? varint.decode + const encodeLength = opts?.lengthEncoder ?? varint.encode + + const lpStream: LengthPrefixedStream = { + async read (options?: AbortOptions) { + let dataLength: number = -1 + const lengthBuffer = new Uint8ArrayList() + + while (true) { + const buf = await bytes.read({ + ...options, + bytes: 1 + }) + + // the underlying resource closed gracefully + if (buf == null) { + break + } + + // read one byte at a time until we can decode a varint + lengthBuffer.append(buf) + + try { + dataLength = decodeLength(lengthBuffer) + } catch (err) { + if (err instanceof RangeError) { + continue + } + + throw err + } + + if (dataLength < 0) { + throw new InvalidMessageLengthError('Invalid message length') + } + + if (opts?.maxLengthLength != null && lengthBuffer.byteLength > opts.maxLengthLength) { + throw new InvalidDataLengthLengthError(`Message length length too long - ${lengthBuffer.byteLength} > ${opts.maxLengthLength}`) + } + + if (dataLength > -1) { + break + } + } + + if (opts?.maxDataLength != null && dataLength > opts.maxDataLength) { + throw new InvalidDataLengthError(`Message length too long - ${dataLength} > ${opts.maxDataLength}`) + } + + const buf = await bytes.read({ + ...options, + bytes: dataLength + }) + + if (buf == null) { + throw new UnexpectedEOFError(`Unexpected EOF - tried to read ${dataLength} bytes but the stream closed`) + } + + if (buf.byteLength !== dataLength) { + throw new UnexpectedEOFError(`Unexpected EOF - read ${buf.byteLength}/${dataLength} bytes before the stream closed`) + } + + return buf + }, + async write (data, options?: AbortOptions) { + // encode, write + await bytes.write(new Uint8ArrayList(encodeLength(data.byteLength), data), options) + }, + async writeV (data, options?: AbortOptions) { + const list = new Uint8ArrayList( + ...data.flatMap(buf => ([encodeLength(buf.byteLength), buf])) + ) + + // encode, write + await bytes.write(list, options) + }, + unwrap () { + return bytes.unwrap() + } + } + + return lpStream +} + +/** + * A protobuf decoder - takes a byte array and returns an object + */ +export interface ProtobufDecoder { + (data: Uint8Array | Uint8ArrayList): T +} + +/** + * A protobuf encoder - takes an object and returns a byte array + */ +export interface ProtobufEncoder { + (data: T): Uint8Array +} + +/** + * Convenience methods for working with protobuf streams + */ +export interface ProtobufStream { + /** + * Read the next length-prefixed byte array from the stream and decode it as the passed protobuf format + */ + read(proto: { decode: ProtobufDecoder }, options?: AbortOptions): Promise + + /** + * Encode the passed object as a protobuf message and write it's length-prefixed bytes to the stream + */ + write(data: T, proto: { encode: ProtobufEncoder }, options?: AbortOptions): Promise + + /** + * Encode the passed objects as protobuf messages and write their length-prefixed bytes to the stream as a single write + */ + writeV(input: T[], proto: { encode: ProtobufEncoder }, options?: AbortOptions): Promise + + /** + * Returns an object with read/write methods for operating on one specific type of protobuf message + */ + pb(proto: { encode: ProtobufEncoder, decode: ProtobufDecoder }): ProtobufMessageStream + + /** + * Returns the underlying stream + */ + unwrap(): Stream +} + +/** + * A message reader/writer that only uses one type of message + */ +export interface ProtobufMessageStream { + /** + * Read a message from the stream + */ + read(options?: AbortOptions): Promise + + /** + * Write a message to the stream + */ + write(d: T, options?: AbortOptions): Promise + + /** + * Write several messages to the stream + */ + writeV(d: T[], options?: AbortOptions): Promise + + /** + * Unwrap the underlying protobuf stream + */ + unwrap(): ProtobufStream +} + +export interface ProtobufStreamOpts extends LengthPrefixedStreamOpts { + +} + +export function pbStream (stream: Stream, opts?: Partial): ProtobufStream { + const lp = lpStream(stream, opts) + + const pbStream: ProtobufStream = { + read: async (proto, options?: AbortOptions) => { + // readLP, decode + const value = await lp.read(options) + + return proto.decode(value) + }, + write: async (message, proto, options?: AbortOptions) => { + // encode, writeLP + await lp.write(proto.encode(message), options) + }, + writeV: async (messages, proto, options?: AbortOptions) => { + // encode, writeLP + await lp.writeV(messages.map(message => proto.encode(message)), options) + }, + pb: (proto) => { + return { + read: async (options) => pbStream.read(proto, options), + write: async (d, options) => pbStream.write(d, proto, options), + writeV: async (d, options) => pbStream.writeV(d, proto, options), + unwrap: () => pbStream + } + }, + unwrap: () => { + return lp.unwrap() + } + } + + return pbStream +} + +export function echo (channel: MessageStream): ReturnType { + channel.addEventListener('remoteCloseWrite', () => { + channel.closeWrite() + }) + + return pipe(channel, channel) +} + +export type PipeInput = Iterable | AsyncIterable | MessageStream + +function isMessageStream (obj?: any): obj is MessageStream { + return obj?.addEventListener != null +} + +export function messageStreamToDuplex (stream: MessageStream): Duplex, Iterable | AsyncIterable> { + const source = pushable() + const onError = Promise.withResolvers>() + + const onMessage = (evt: StreamMessageEvent): void => { + source.push(evt.data) + } + + const onRemoteCloseWrite = (): void => { + source.end() + + stream.removeEventListener('message', onMessage) + stream.removeEventListener('close', onClose) + stream.removeEventListener('remoteCloseWrite', onRemoteCloseWrite) + } + + const onClose = (evt: StreamCloseEvent): void => { + source.end(evt.error) + + if (evt.error != null) { + onError.reject(evt.error) + } + + stream.removeEventListener('message', onMessage) + stream.removeEventListener('close', onClose) + stream.removeEventListener('remoteCloseWrite', onRemoteCloseWrite) + } + + stream.addEventListener('message', onMessage) + stream.addEventListener('close', onClose, { + once: true + }) + stream.addEventListener('remoteCloseWrite', onRemoteCloseWrite, { + once: true + }) + + return { + source, + async sink (source: Source) { + async function * toGenerator (): AsyncGenerator { + yield * source + } + + const gen = toGenerator() + + while (true) { + const { done, value } = await Promise.race([ + gen.next(), + onError.promise + ]) + + if (value != null) { + if (!stream.send(value)) { + await Promise.race([ + pEvent(stream, 'drain', { + rejectionEvents: [ + 'close' + ] + }) + ]) + } + } + + if (done === true) { + break + } + } + + await stream.closeWrite() + } + } +} + +interface SourceFn { (): A } + +type PipeSource = + Iterable | + AsyncIterable | + SourceFn | + Duplex | + MessageStream + +type PipeTransform = + Transform | + Duplex | + MessageStream + +type PipeSink = + Sink | + Duplex | + MessageStream + +type PipeOutput = + A extends Sink ? ReturnType : + A extends Duplex ? ReturnType : + A extends MessageStream ? AsyncGenerator : + never + +// single item pipe output includes pipe source types +type SingleItemPipeOutput = + A extends Iterable ? A : + A extends AsyncIterable ? A : + A extends SourceFn ? ReturnType : + A extends Duplex ? A['source'] : + PipeOutput + +type PipeFnInput = + A extends Iterable ? A : + A extends AsyncIterable ? A : + A extends SourceFn ? ReturnType : + A extends Transform ? ReturnType : + A extends Duplex ? A['source'] : + never + +export function pipe< + A extends PipeSource +> ( + source: A +): SingleItemPipeOutput +// two items, source to sink +export function pipe< + A extends PipeSource, + B extends PipeSink> +> ( + source: A, + sink: B +): PipeOutput + +// three items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeSink> +> ( + source: A, + transform1: B, + sink: C +): PipeOutput + +// many items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + sink: D +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + sink: E +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeTransform>, + F extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + transform4: E, + sink: F +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeTransform>, + F extends PipeTransform>, + G extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + transform4: E, + transform5: F, + sink: G +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeTransform>, + F extends PipeTransform>, + G extends PipeTransform>, + H extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + transform4: E, + transform5: F, + transform6: G, + sink: H +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeTransform>, + F extends PipeTransform>, + G extends PipeTransform>, + H extends PipeTransform>, + I extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + transform4: E, + transform5: F, + transform6: G, + transform7: H, + sink: I +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeTransform>, + F extends PipeTransform>, + G extends PipeTransform>, + H extends PipeTransform>, + I extends PipeTransform>, + J extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + transform4: E, + transform5: F, + transform6: G, + transform7: H, + transform8: I, + sink: J +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeTransform>, + F extends PipeTransform>, + G extends PipeTransform>, + H extends PipeTransform>, + I extends PipeTransform>, + J extends PipeTransform>, + K extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + transform4: E, + transform5: F, + transform6: G, + transform7: H, + transform8: I, + transform9: J, + sink: K +): PipeOutput + +// lots of items, source to sink with transform(s) in between +export function pipe< + A extends PipeSource, + B extends PipeTransform>, + C extends PipeTransform>, + D extends PipeTransform>, + E extends PipeTransform>, + F extends PipeTransform>, + G extends PipeTransform>, + H extends PipeTransform>, + I extends PipeTransform>, + J extends PipeTransform>, + K extends PipeTransform>, + L extends PipeSink> +> ( + source: A, + transform1: B, + transform2: C, + transform3: D, + transform4: E, + transform5: F, + transform6: G, + transform7: H, + transform8: I, + transform9: J, + transform10: K, + sink: L +): PipeOutput +export function pipe (...input: any[]): any { + const sources = input.map(source => { + if (isMessageStream(source)) { + return messageStreamToDuplex(source) + } + + return source + }) + + // @ts-expect-error it-pipe types say args cannot be spread like this + return itPipe(...sources) +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/tracked-list.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/tracked-list.ts new file mode 100644 index 000000000..e1b884950 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/tracked-list.ts @@ -0,0 +1,26 @@ +import type { Metrics } from '@libp2p/interface' + +export interface CreateTrackedListInit { + /** + * The metric name to use + */ + name: string + + /** + * A metrics implementation + */ + metrics?: Metrics +} + +export function trackedList (config: CreateTrackedListInit): V[] { + const { name, metrics } = config + const list: V[] = [] + + metrics?.registerMetric(name, { + calculate: () => { + return list.length + } + }) + + return list +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/tracked-map.ts b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/tracked-map.ts new file mode 100644 index 000000000..566abd5fd --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/src/tracked-map.ts @@ -0,0 +1,65 @@ +import type { Metric, Metrics } from '@libp2p/interface' + +export interface TrackedMapInit { + name: string + metrics: Metrics +} + +class TrackedMap extends Map { + private readonly metric: Metric + + constructor (init: TrackedMapInit) { + super() + + const { name, metrics } = init + + this.metric = metrics.registerMetric(name) + this.updateComponentMetric() + } + + set (key: K, value: V): this { + super.set(key, value) + this.updateComponentMetric() + return this + } + + delete (key: K): boolean { + const deleted = super.delete(key) + this.updateComponentMetric() + return deleted + } + + clear (): void { + super.clear() + this.updateComponentMetric() + } + + private updateComponentMetric (): void { + this.metric.update(this.size) + } +} + +export interface CreateTrackedMapInit { + /** + * The metric name to use + */ + name: string + + /** + * A metrics implementation + */ + metrics?: Metrics +} + +export function trackedMap (config: CreateTrackedMapInit): Map { + const { name, metrics } = config + let map: Map + + if (metrics != null) { + map = new TrackedMap({ name, metrics }) + } else { + map = new Map() + } + + return map +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/tsconfig.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/tsconfig.json new file mode 100644 index 000000000..5fe8ea40d --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/typedoc.json b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/typedoc.json new file mode 100644 index 000000000..acfd7056e --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/libp2p/packages/utils/typedoc.json @@ -0,0 +1,38 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts", + "./src/abort-options.ts", + "./src/abstract-stream.ts", + "./src/adaptive-timeout.ts", + "./src/array-equals.ts", + "./src/close.ts", + "./src/close-source.ts", + "./src/debounce.ts", + "./src/filters/index.ts", + "./src/get-thin-waist-addresses.ts", + "./src/global-unicast-ip.ts", + "./src/ip-port-to-multiaddr.ts", + "./src/is-async-generator.ts", + "./src/is-generator.ts", + "./src/is-promise.ts", + "./src/link-local-ip.ts", + "./src/merge-options.ts", + "./src/moving-average.ts", + "./src/multiaddr/is-global-unicast.ts", + "./src/multiaddr/is-ip-based.ts", + "./src/multiaddr/is-link-local.ts", + "./src/multiaddr/is-loopback.ts", + "./src/multiaddr/is-network-address.ts", + "./src/multiaddr/is-private.ts", + "./src/peer-queue.ts", + "./src/priority-queue.ts", + "./src/private-ip.ts", + "./src/queue/index.ts", + "./src/rate-limiter.ts", + "./src/repeating-task.ts", + "./src/stream-to-ma-conn.ts", + "./src/tracked-list.ts", + "./src/tracked-map.ts" + ] +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/package-lock.json b/perf/impl/js-libp2p/v2.8-eventtarget/package-lock.json new file mode 100644 index 000000000..4e1e568ad --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/package-lock.json @@ -0,0 +1,250 @@ +{ + "name": "@libp2p/perf-js-libp2p-2-8", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@libp2p/perf-js-libp2p-2-8", + "dependencies": { + "@multiformats/multiaddr": "^12.4.0" + } + }, + "node_modules/@chainsafe/is-ip": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@chainsafe/is-ip/-/is-ip-2.1.0.tgz", + "integrity": "sha512-KIjt+6IfysQ4GCv66xihEitBjvhU/bixbbbFxdJ1sqCp4uJ0wuZiYBPhksZoy4lfaF0k9cwNzY5upEW/VWdw3w==", + "license": "MIT" + }, + "node_modules/@chainsafe/netmask": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@chainsafe/netmask/-/netmask-2.0.0.tgz", + "integrity": "sha512-I3Z+6SWUoaljh3TBzCnCxjlUyN8tA+NAk5L6m9IxvCf1BENQTePzPMis97CoN/iMW1St3WN+AWCCRp+TTBRiDg==", + "license": "MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.5.tgz", + "integrity": "sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==", + "license": "MIT" + }, + "node_modules/@multiformats/dns": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@multiformats/dns/-/dns-1.0.6.tgz", + "integrity": "sha512-nt/5UqjMPtyvkG9BQYdJ4GfLK3nMqGpFZOzf4hAmIa0sJh2LlS9YKXZ4FgwBDsaHvzZqR/rUFIywIc7pkHNNuw==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@types/dns-packet": "^5.6.5", + "buffer": "^6.0.3", + "dns-packet": "^5.6.1", + "hashlru": "^2.3.0", + "p-queue": "^8.0.1", + "progress-events": "^1.0.0", + "uint8arrays": "^5.0.2" + } + }, + "node_modules/@multiformats/multiaddr": { + "version": "12.5.1", + "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.5.1.tgz", + "integrity": "sha512-+DDlr9LIRUS8KncI1TX/FfUn8F2dl6BIxJgshS/yFQCNB5IAF0OGzcwB39g5NLE22s4qqDePv0Qof6HdpJ/4aQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "@chainsafe/is-ip": "^2.0.1", + "@chainsafe/netmask": "^2.0.0", + "@multiformats/dns": "^1.0.3", + "abort-error": "^1.0.1", + "multiformats": "^13.0.0", + "uint8-varint": "^2.0.1", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/@types/dns-packet": { + "version": "5.6.5", + "resolved": "https://registry.npmjs.org/@types/dns-packet/-/dns-packet-5.6.5.tgz", + "integrity": "sha512-qXOC7XLOEe43ehtWJCMnQXvgcIpv6rPmQ1jXT98Ad8A3TB1Ue50jsCbSSSyuazScEuZ/Q026vHbrOTVkmwA+7Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "24.2.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz", + "integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==", + "license": "MIT", + "dependencies": { + "undici-types": "~7.10.0" + } + }, + "node_modules/abort-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/abort-error/-/abort-error-1.0.1.tgz", + "integrity": "sha512-fxqCblJiIPdSXIUrxI0PL+eJG49QdP9SQ70qtB65MVAoMr2rASlOyAbJFOylfB467F/f+5BCLJJq58RYi7mGfg==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "license": "MIT", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/hashlru": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/hashlru/-/hashlru-2.3.0.tgz", + "integrity": "sha512-0cMsjjIC8I+D3M44pOQdsy0OHXGLVz6Z0beRuufhKa0KfaD2wGwAev6jILzXsd3/vpnNQJmWyZtIILqM1N+n5A==", + "license": "MIT" + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/multiformats": { + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.4.0.tgz", + "integrity": "sha512-Mkb/QcclrJxKC+vrcIFl297h52QcKh2Az/9A5vbWytbQt4225UWWWmIuSsKksdww9NkIeYcA7DkfftyLuC/JSg==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/p-queue": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.0.tgz", + "integrity": "sha512-mxLDbbGIBEXTJL0zEx8JIylaj3xQ7Z/7eEVjcF9fJX4DBiH9oqe+oahYnlKKxm0Ci9TlWTyhSHgygxMxjIB2jw==", + "license": "MIT", + "dependencies": { + "eventemitter3": "^5.0.1", + "p-timeout": "^6.1.2" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-timeout": { + "version": "6.1.4", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", + "integrity": "sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==", + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/progress-events": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/progress-events/-/progress-events-1.0.1.tgz", + "integrity": "sha512-MOzLIwhpt64KIVN64h1MwdKWiyKFNc/S6BoYKPIVUHFg0/eIEyBulhWCgn678v/4c0ri3FdGuzXymNCv02MUIw==", + "license": "Apache-2.0 OR MIT" + }, + "node_modules/uint8-varint": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/uint8-varint/-/uint8-varint-2.0.4.tgz", + "integrity": "sha512-FwpTa7ZGA/f/EssWAb5/YV6pHgVF1fViKdW8cWaEarjB8t7NyofSWBdOTyFPaGuUG4gx3v1O3PQ8etsiOs3lcw==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arraylist": "^2.0.0", + "uint8arrays": "^5.0.0" + } + }, + "node_modules/uint8arraylist": { + "version": "2.4.8", + "resolved": "https://registry.npmjs.org/uint8arraylist/-/uint8arraylist-2.4.8.tgz", + "integrity": "sha512-vc1PlGOzglLF0eae1M8mLRTBivsvrGsdmJ5RbK3e+QRvRLOZfZhQROTwH/OfyF3+ZVUg9/8hE8bmKP2CvP9quQ==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "uint8arrays": "^5.0.1" + } + }, + "node_modules/uint8arrays": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/uint8arrays/-/uint8arrays-5.1.0.tgz", + "integrity": "sha512-vA6nFepEmlSKkMBnLBaUMVvAC4G3CTmO58C12y4sq6WPDOR7mOFYOi7GlrQ4djeSbP6JG9Pv9tJDM97PedRSww==", + "license": "Apache-2.0 OR MIT", + "dependencies": { + "multiformats": "^13.0.0" + } + }, + "node_modules/undici-types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", + "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==", + "license": "MIT" + } + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/package.json b/perf/impl/js-libp2p/v2.8-eventtarget/package.json new file mode 100644 index 000000000..4e0d2f08b --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/package.json @@ -0,0 +1,9 @@ +{ + "name": "@libp2p/perf-js-libp2p-2-8-eventtarget", + "private": true, + "main": "index.js", + "type": "module", + "dependencies": { + "@multiformats/multiaddr": "^12.4.0" + } +} diff --git a/perf/impl/js-libp2p/v2.8-eventtarget/perf b/perf/impl/js-libp2p/v2.8-eventtarget/perf new file mode 100755 index 000000000..1a3e19c51 --- /dev/null +++ b/perf/impl/js-libp2p/v2.8-eventtarget/perf @@ -0,0 +1,45 @@ +#!/bin/bash + +# In case this script is `kill`ed, `kill` its child process, namely the `node` +# process below. +cleanup() { + kill $node_pid +} +trap cleanup EXIT TERM + +# Find the path to the Node.js executable +node_path=$(which node) + +run_server=false +server_address="" +upload_bytes=0 +download_bytes=0 +transport="" + +# Parse named parameters manually +for ((i = 1; i <= $#; i++)); do + if [ "${!i}" == "--server-address" ]; then + server_address="${@:i+1:1}" + fi + if [ "${!i}" == "--upload-bytes" ]; then + upload_bytes="${@:i+1:1}" + fi + if [ "${!i}" == "--download-bytes" ]; then + download_bytes="${@:i+1:1}" + fi + if [ "${!i}" == "--transport" ]; then + transport="${@:i+1:1}" + fi + if [ "${!i}" == "--run-server" ]; then + run_server=true + fi +done + +# Run perf +node $(dirname "$0")/index.js --run-server=$run_server --server-address=$server_address --upload-bytes=$upload_bytes --download-bytes=$download_bytes --transport=$transport & + +node_pid=$! + +# Wait for `node_pid` to finish, or for it to be `kill`ed by the above +# `cleanup`. +wait $node_pid diff --git a/perf/runner/benchmark-results.json b/perf/runner/benchmark-results.json index 271cc31c5..28e85e655 100644 --- a/perf/runner/benchmark-results.json +++ b/perf/runner/benchmark-results.json @@ -8,25985 +8,5822 @@ "result": [ { "type": "intermediary", - "timeSeconds": 1.000016698, - "uploadBytes": 103546880, + "timeSeconds": 1.001, + "uploadBytes": 77463552, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000014295, - "uploadBytes": 220856320, + "timeSeconds": 1.001, + "uploadBytes": 236847104, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00012581, - "uploadBytes": 223707136, + "timeSeconds": 1.001, + "uploadBytes": 261160960, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000036013, - "uploadBytes": 221921280, + "timeSeconds": 1.001, + "uploadBytes": 263979008, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000045772, - "uploadBytes": 222429184, + "timeSeconds": 1.001, + "uploadBytes": 263979008, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000009095, - "uploadBytes": 222314496, + "timeSeconds": 1.001, + "uploadBytes": 256311296, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000077646, - "uploadBytes": 222461952, + "timeSeconds": 1.001, + "uploadBytes": 239534080, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000617321, - "uploadBytes": 194445312, + "timeSeconds": 1.001, + "uploadBytes": 244056064, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000604671, - "uploadBytes": 76267520, + "timeSeconds": 1.001, + "uploadBytes": 235405312, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.002994949, - "uploadBytes": 77348864, + "timeSeconds": 1.002, + "uploadBytes": 226754560, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000375013, - "uploadBytes": 77561856, + "timeSeconds": 1.001, + "uploadBytes": 226295808, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000060701, - "uploadBytes": 77250560, + "timeSeconds": 1.001, + "uploadBytes": 240844800, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000077234, - "uploadBytes": 77479936, + "timeSeconds": 1.001, + "uploadBytes": 229441536, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000022218, - "uploadBytes": 77627392, + "timeSeconds": 1.001, + "uploadBytes": 236650496, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000119138, - "uploadBytes": 77971456, + "timeSeconds": 1.002, + "uploadBytes": 234094592, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000220831, - "uploadBytes": 78741504, + "timeSeconds": 1.001, + "uploadBytes": 235339776, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000034371, - "uploadBytes": 79085568, + "timeSeconds": 1.001, + "uploadBytes": 238485504, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000032886, - "uploadBytes": 78708736, + "timeSeconds": 1.001, + "uploadBytes": 238157824, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00008873, - "uploadBytes": 79265792, + "timeSeconds": 1.001, + "uploadBytes": 232456192, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000334872, - "uploadBytes": 103022592, + "timeSeconds": 1.002, + "uploadBytes": 78184448, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000050094, - "uploadBytes": 221036544, + "timeSeconds": 1.001, + "uploadBytes": 244449280, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000038453, - "uploadBytes": 223019008, + "timeSeconds": 1.001, + "uploadBytes": 271384576, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000001317, - "uploadBytes": 222380032, + "timeSeconds": 1.001, + "uploadBytes": 269615104, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000512362, - "uploadBytes": 221184000, + "timeSeconds": 1.001, + "uploadBytes": 274726912, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000025377, - "uploadBytes": 222593024, + "timeSeconds": 1.001, + "uploadBytes": 264437760, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000041221, - "uploadBytes": 221724672, + "timeSeconds": 1.001, + "uploadBytes": 270925824, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000021797, - "uploadBytes": 220528640, + "timeSeconds": 1.001, + "uploadBytes": 269352960, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000037837, - "uploadBytes": 222724096, + "timeSeconds": 1.001, + "uploadBytes": 265027584, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000035082, - "uploadBytes": 220725248, + "timeSeconds": 1.001, + "uploadBytes": 264437760, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000023594, - "uploadBytes": 221511680, + "timeSeconds": 1.001, + "uploadBytes": 259915776, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000005383, - "uploadBytes": 222134272, + "timeSeconds": 1.001, + "uploadBytes": 261816320, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000022695, - "uploadBytes": 220725248, + "timeSeconds": 1.001, + "uploadBytes": 270073856, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000019281, - "uploadBytes": 221806592, + "timeSeconds": 1.001, + "uploadBytes": 270204928, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000128302, - "uploadBytes": 221872128, + "timeSeconds": 1.001, + "uploadBytes": 268894208, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000025699, - "uploadBytes": 215564288, + "timeSeconds": 1.001, + "uploadBytes": 270008320, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000006531, - "uploadBytes": 60489728, + "timeSeconds": 1.001, + "uploadBytes": 272760832, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000494747, - "uploadBytes": 53526528, + "timeSeconds": 1.001, + "uploadBytes": 272105472, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.001897588, - "uploadBytes": 54345728, + "timeSeconds": 1.001, + "uploadBytes": 273547264, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000053705, - "uploadBytes": 105021440, + "timeSeconds": 1.001, + "uploadBytes": 93650944, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000058176, - "uploadBytes": 222593024, + "timeSeconds": 1.001, + "uploadBytes": 247463936, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000284663, - "uploadBytes": 223789056, + "timeSeconds": 1.001, + "uploadBytes": 271777792, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000025977, - "uploadBytes": 224428032, + "timeSeconds": 1.001, + "uploadBytes": 278724608, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000025249, - "uploadBytes": 223248384, + "timeSeconds": 1.001, + "uploadBytes": 278462464, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000036954, - "uploadBytes": 222822400, + "timeSeconds": 1.001, + "uploadBytes": 260702208, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000028935, - "uploadBytes": 223330304, + "timeSeconds": 1.001, + "uploadBytes": 243007488, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00001482, - "uploadBytes": 207093760, + "timeSeconds": 1.001, + "uploadBytes": 239796224, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000017669, - "uploadBytes": 75808768, + "timeSeconds": 1.001, + "uploadBytes": 244121600, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000053912, - "uploadBytes": 76988416, + "timeSeconds": 1.001, + "uploadBytes": 234881024, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000331254, - "uploadBytes": 77119488, + "timeSeconds": 1.001, + "uploadBytes": 238682112, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000417338, - "uploadBytes": 77807616, + "timeSeconds": 1.001, + "uploadBytes": 240254976, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000532885, - "uploadBytes": 78151680, + "timeSeconds": 1.001, + "uploadBytes": 245694464, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000173139, - "uploadBytes": 78495744, + "timeSeconds": 1.001, + "uploadBytes": 246743040, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000132041, - "uploadBytes": 78331904, + "timeSeconds": 1.002, + "uploadBytes": 250937344, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000152239, - "uploadBytes": 78708736, + "timeSeconds": 1.001, + "uploadBytes": 248774656, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000004109, - "uploadBytes": 78807040, + "timeSeconds": 1.004, + "uploadBytes": 245170176, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000532774, - "uploadBytes": 79233024, + "timeSeconds": 1.004, + "uploadBytes": 247857152, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000033154, - "uploadBytes": 79462400, + "timeSeconds": 1.001, + "uploadBytes": 243269632, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000067956, - "uploadBytes": 105824256, + "timeSeconds": 1.001, + "uploadBytes": 92471296, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000040292, - "uploadBytes": 223756288, + "timeSeconds": 1.001, + "uploadBytes": 249495552, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000006343, - "uploadBytes": 224067584, + "timeSeconds": 1.001, + "uploadBytes": 264699904, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000010432, - "uploadBytes": 224673792, + "timeSeconds": 1.001, + "uploadBytes": 261750784, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000007122, - "uploadBytes": 224641024, + "timeSeconds": 1.001, + "uploadBytes": 263651328, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000027946, - "uploadBytes": 224526336, + "timeSeconds": 1.001, + "uploadBytes": 262799360, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00007898, - "uploadBytes": 223920128, + "timeSeconds": 1.001, + "uploadBytes": 241303552, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000206203, - "uploadBytes": 205914112, + "timeSeconds": 1.001, + "uploadBytes": 255197184, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000026518, - "uploadBytes": 76496896, + "timeSeconds": 1.001, + "uploadBytes": 258736128, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000055385, - "uploadBytes": 77479936, + "timeSeconds": 1.001, + "uploadBytes": 243466240, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00002412, - "uploadBytes": 77692928, + "timeSeconds": 1.001, + "uploadBytes": 238288896, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000284027, - "uploadBytes": 77807616, + "timeSeconds": 1.001, + "uploadBytes": 242089984, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000261027, - "uploadBytes": 78315520, + "timeSeconds": 1.001, + "uploadBytes": 247463936, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000279964, - "uploadBytes": 78544896, + "timeSeconds": 1.001, + "uploadBytes": 235143168, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000122241, - "uploadBytes": 78807040, + "timeSeconds": 1.001, + "uploadBytes": 231931904, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000090992, - "uploadBytes": 79134720, + "timeSeconds": 1.001, + "uploadBytes": 240254976, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000092308, - "uploadBytes": 79380480, + "timeSeconds": 1.001, + "uploadBytes": 232390656, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000114819, - "uploadBytes": 79806464, + "timeSeconds": 1.001, + "uploadBytes": 229572608, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000461593, - "uploadBytes": 80052224, + "timeSeconds": 1.001, + "uploadBytes": 248119296, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00015407, - "uploadBytes": 78086144, + "timeSeconds": 1.001, + "uploadBytes": 88670208, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000088012, - "uploadBytes": 74252288, + "timeSeconds": 1.001, + "uploadBytes": 242221056, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.006007958, - "uploadBytes": 75857920, + "timeSeconds": 1.001, + "uploadBytes": 255655936, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00058352, - "uploadBytes": 75759616, + "timeSeconds": 1.001, + "uploadBytes": 260964352, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000358077, - "uploadBytes": 75153408, + "timeSeconds": 1.001, + "uploadBytes": 263585792, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000037993, - "uploadBytes": 75726848, + "timeSeconds": 1.001, + "uploadBytes": 260898816, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000032086, - "uploadBytes": 75939840, + "timeSeconds": 1.001, + "uploadBytes": 262668288, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000060264, - "uploadBytes": 76906496, + "timeSeconds": 1.001, + "uploadBytes": 263716864, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000024842, - "uploadBytes": 76087296, + "timeSeconds": 1.001, + "uploadBytes": 243531776, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000470976, - "uploadBytes": 76627968, + "timeSeconds": 1.001, + "uploadBytes": 252903424, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000012511, - "uploadBytes": 77201408, + "timeSeconds": 1.001, + "uploadBytes": 252575744, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000008967, - "uploadBytes": 77594624, + "timeSeconds": 1.001, + "uploadBytes": 256311296, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000389647, - "uploadBytes": 77119488, + "timeSeconds": 1.001, + "uploadBytes": 256638976, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000594355, - "uploadBytes": 77922304, + "timeSeconds": 1.001, + "uploadBytes": 254083072, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.0000223, - "uploadBytes": 78086144, + "timeSeconds": 1.001, + "uploadBytes": 256573440, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000262745, - "uploadBytes": 78200832, + "timeSeconds": 1.001, + "uploadBytes": 250740736, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000259101, - "uploadBytes": 78118912, + "timeSeconds": 1.001, + "uploadBytes": 255459328, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000586718, - "uploadBytes": 78790656, + "timeSeconds": 1.001, + "uploadBytes": 258539520, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000059605, - "uploadBytes": 79052800, + "timeSeconds": 1.001, + "uploadBytes": 259719168, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000027844, - "uploadBytes": 110149632, + "timeSeconds": 1.028, + "uploadBytes": 84017152, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000036929, - "uploadBytes": 226557952, + "timeSeconds": 1.001, + "uploadBytes": 246939648, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000021519, - "uploadBytes": 227753984, + "timeSeconds": 1.001, + "uploadBytes": 247857152, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000043606, - "uploadBytes": 227999744, + "timeSeconds": 1.001, + "uploadBytes": 258211840, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000000229, - "uploadBytes": 228311040, + "timeSeconds": 1.001, + "uploadBytes": 258146304, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000000331, - "uploadBytes": 228032512, + "timeSeconds": 1.001, + "uploadBytes": 258539520, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000023663, - "uploadBytes": 227573760, + "timeSeconds": 1.001, + "uploadBytes": 252772352, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000099501, - "uploadBytes": 211812352, + "timeSeconds": 1.001, + "uploadBytes": 259260416, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000000583, - "uploadBytes": 159809536, + "timeSeconds": 1.001, + "uploadBytes": 265945088, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000177036, - "uploadBytes": 160432128, + "timeSeconds": 1.001, + "uploadBytes": 266469376, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000047658, - "uploadBytes": 160661504, + "timeSeconds": 1.001, + "uploadBytes": 266338304, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000233619, - "uploadBytes": 159776768, + "timeSeconds": 1.001, + "uploadBytes": 269156352, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000009561, - "uploadBytes": 160071680, + "timeSeconds": 1.001, + "uploadBytes": 269680640, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000125037, - "uploadBytes": 160694272, + "timeSeconds": 1.001, + "uploadBytes": 268828672, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000064317, - "uploadBytes": 160677888, + "timeSeconds": 1.001, + "uploadBytes": 269221888, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000035647, - "uploadBytes": 161464320, + "timeSeconds": 1.001, + "uploadBytes": 268632064, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000044697, - "uploadBytes": 161677312, + "timeSeconds": 1.001, + "uploadBytes": 269025280, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000090258, - "uploadBytes": 161677312, + "timeSeconds": 1.001, + "uploadBytes": 269090816, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000005578, - "uploadBytes": 161562624, + "timeSeconds": 1.001, + "uploadBytes": 268828672, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000026427, - "uploadBytes": 102612992, + "timeSeconds": 1.001, + "uploadBytes": 77463552, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000005009, - "uploadBytes": 220626944, + "timeSeconds": 1.001, + "uploadBytes": 251068416, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000030096, - "uploadBytes": 222167040, + "timeSeconds": 1.001, + "uploadBytes": 256835584, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000066893, - "uploadBytes": 221396992, + "timeSeconds": 1.001, + "uploadBytes": 260440064, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000127442, - "uploadBytes": 221462528, + "timeSeconds": 1.001, + "uploadBytes": 259784704, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.005465779, - "uploadBytes": 144293888, + "timeSeconds": 1.002, + "uploadBytes": 252116992, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000023538, - "uploadBytes": 77086720, + "timeSeconds": 1.001, + "uploadBytes": 254541824, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000031021, - "uploadBytes": 76414976, + "timeSeconds": 1.001, + "uploadBytes": 255524864, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000428844, - "uploadBytes": 76660736, + "timeSeconds": 1.001, + "uploadBytes": 247857152, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000203116, - "uploadBytes": 76922880, + "timeSeconds": 1.001, + "uploadBytes": 247005184, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00106409, - "uploadBytes": 77938688, + "timeSeconds": 1.001, + "uploadBytes": 254869504, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000011239, - "uploadBytes": 77578240, + "timeSeconds": 1.001, + "uploadBytes": 252313600, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000090995, - "uploadBytes": 77660160, + "timeSeconds": 1.001, + "uploadBytes": 252182528, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000023043, - "uploadBytes": 78069760, + "timeSeconds": 1.001, + "uploadBytes": 248381440, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00010705, - "uploadBytes": 78741504, + "timeSeconds": 1.001, + "uploadBytes": 250347520, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000183502, - "uploadBytes": 78200832, + "timeSeconds": 1.001, + "uploadBytes": 258605056, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000191926, - "uploadBytes": 78888960, + "timeSeconds": 1.001, + "uploadBytes": 255655936, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000603755, - "uploadBytes": 79364096, + "timeSeconds": 1.001, + "uploadBytes": 259129344, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000246798, - "uploadBytes": 79642624, + "timeSeconds": 1.001, + "uploadBytes": 255000576, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000042941, - "uploadBytes": 104202240, + "timeSeconds": 1.003, + "uploadBytes": 87949312, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000013567, - "uploadBytes": 220921856, + "timeSeconds": 1.001, + "uploadBytes": 237043712, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000068627, - "uploadBytes": 223723520, + "timeSeconds": 1.001, + "uploadBytes": 250478592, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000047996, - "uploadBytes": 222363648, + "timeSeconds": 1.001, + "uploadBytes": 254214144, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.002884856, - "uploadBytes": 163823616, + "timeSeconds": 1.001, + "uploadBytes": 255524864, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.006625377, - "uploadBytes": 77611008, + "timeSeconds": 1.001, + "uploadBytes": 262144000, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000227679, - "uploadBytes": 77709312, + "timeSeconds": 1.001, + "uploadBytes": 261619712, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.0000899, - "uploadBytes": 76939264, + "timeSeconds": 1.001, + "uploadBytes": 263520256, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000085205, - "uploadBytes": 77283328, + "timeSeconds": 1.001, + "uploadBytes": 241762304, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000574224, - "uploadBytes": 77578240, + "timeSeconds": 1.001, + "uploadBytes": 247791616, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000362562, - "uploadBytes": 77742080, + "timeSeconds": 1.001, + "uploadBytes": 253231104, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000095285, - "uploadBytes": 78381056, + "timeSeconds": 1.001, + "uploadBytes": 256901120, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000512136, - "uploadBytes": 78938112, + "timeSeconds": 1.001, + "uploadBytes": 256376832, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000712828, - "uploadBytes": 78430208, + "timeSeconds": 1.001, + "uploadBytes": 258342912, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000054368, - "uploadBytes": 78872576, + "timeSeconds": 1.001, + "uploadBytes": 255655936, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000173732, - "uploadBytes": 79380480, + "timeSeconds": 1.001, + "uploadBytes": 256573440, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000032124, - "uploadBytes": 79495168, + "timeSeconds": 1.001, + "uploadBytes": 252706816, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000055393, - "uploadBytes": 80019456, + "timeSeconds": 1.001, + "uploadBytes": 251461632, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000047315, - "uploadBytes": 79953920, + "timeSeconds": 1.001, + "uploadBytes": 255459328, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000036019, - "uploadBytes": 98779136, + "timeSeconds": 1.001, + "uploadBytes": 70385664, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00003427, - "uploadBytes": 219348992, + "timeSeconds": 1.001, + "uploadBytes": 252903424, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000031953, - "uploadBytes": 219267072, + "timeSeconds": 1.002, + "uploadBytes": 266665984, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000027779, - "uploadBytes": 219103232, + "timeSeconds": 1.001, + "uploadBytes": 266731520, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000011793, - "uploadBytes": 220069888, + "timeSeconds": 1.001, + "uploadBytes": 254083072, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000106338, - "uploadBytes": 218284032, + "timeSeconds": 1.001, + "uploadBytes": 263061504, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000158874, - "uploadBytes": 219643904, + "timeSeconds": 1.001, + "uploadBytes": 252116992, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000107443, - "uploadBytes": 218365952, + "timeSeconds": 1.001, + "uploadBytes": 246087680, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000028171, - "uploadBytes": 219267072, + "timeSeconds": 1.001, + "uploadBytes": 227737600, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000157602, - "uploadBytes": 218349568, + "timeSeconds": 1.001, + "uploadBytes": 250150912, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000099372, - "uploadBytes": 219480064, + "timeSeconds": 1.002, + "uploadBytes": 255000576, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000108422, - "uploadBytes": 218546176, + "timeSeconds": 1.001, + "uploadBytes": 248446976, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000019342, - "uploadBytes": 219348992, + "timeSeconds": 1.001, + "uploadBytes": 259063808, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000021503, - "uploadBytes": 218775552, + "timeSeconds": 1.001, + "uploadBytes": 253034496, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000019977, - "uploadBytes": 218808320, + "timeSeconds": 1.001, + "uploadBytes": 252379136, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000018838, - "uploadBytes": 218890240, + "timeSeconds": 1.001, + "uploadBytes": 260308992, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000044813, - "uploadBytes": 218972160, + "timeSeconds": 1.001, + "uploadBytes": 260898816, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000037716, - "uploadBytes": 218988544, + "timeSeconds": 1.001, + "uploadBytes": 258998272, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000001058, - "uploadBytes": 218644480, + "timeSeconds": 1.002, + "uploadBytes": 254345216, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.001367907, - "uploadBytes": 98107392, + "timeSeconds": 1.001, + "uploadBytes": 86179840, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000329917, - "uploadBytes": 88571904, + "timeSeconds": 1.001, + "uploadBytes": 245170176, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000118844, - "uploadBytes": 73908224, + "timeSeconds": 1.001, + "uploadBytes": 255393792, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000953241, - "uploadBytes": 74792960, + "timeSeconds": 1.001, + "uploadBytes": 260964352, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000133412, - "uploadBytes": 74956800, + "timeSeconds": 1.001, + "uploadBytes": 260440064, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000230025, - "uploadBytes": 74711040, + "timeSeconds": 1.001, + "uploadBytes": 259522560, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000041316, - "uploadBytes": 75857920, + "timeSeconds": 1.001, + "uploadBytes": 247660544, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000150124, - "uploadBytes": 75497472, + "timeSeconds": 1.001, + "uploadBytes": 254672896, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000541528, - "uploadBytes": 75481088, + "timeSeconds": 1.001, + "uploadBytes": 258998272, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000394855, - "uploadBytes": 76808192, + "timeSeconds": 1.001, + "uploadBytes": 248250368, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.00009961, - "uploadBytes": 76103680, + "timeSeconds": 1.001, + "uploadBytes": 255000576, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000045454, - "uploadBytes": 76496896, + "timeSeconds": 1.001, + "uploadBytes": 256376832, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000105898, - "uploadBytes": 77266944, + "timeSeconds": 1.001, + "uploadBytes": 251068416, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000118322, - "uploadBytes": 76677120, + "timeSeconds": 1.001, + "uploadBytes": 257818624, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000677271, - "uploadBytes": 77381632, + "timeSeconds": 1.001, + "uploadBytes": 254935040, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000583609, - "uploadBytes": 77414400, + "timeSeconds": 1.001, + "uploadBytes": 259850240, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000071241, - "uploadBytes": 77791232, + "timeSeconds": 1.001, + "uploadBytes": 256507904, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000534311, - "uploadBytes": 78118912, + "timeSeconds": 1.001, + "uploadBytes": 258670592, "downloadBytes": 0 }, { "type": "intermediary", - "timeSeconds": 1.000015934, - "uploadBytes": 78135296, + "timeSeconds": 1.001, + "uploadBytes": 250871808, "downloadBytes": 0 } ], - "implementation": "quic-go", - "version": "v0.45", - "transportStack": "quic-v1" + "implementation": "js-libp2p", + "version": "v2.8", + "transportStack": "tcp" }, { "result": [ { - "type": "intermediate", - "timeSeconds": 1.000101159, - "uploadBytes": 61776855, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 76611584, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000082041, - "uploadBytes": 174242816, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 241827840, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000072546, - "uploadBytes": 175605760, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259653632, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000123518, - "uploadBytes": 163913728, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260177920, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000119907, - "uploadBytes": 168227840, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260308992, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000152107, - "uploadBytes": 164961280, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260308992, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000081814, - "uploadBytes": 163902464, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 254738432, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000150619, - "uploadBytes": 170852352, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259457024, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000085032, - "uploadBytes": 172913664, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 256704512, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00011566, - "uploadBytes": 180302848, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259850240, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000065313, - "uploadBytes": 178861056, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259653632, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000068841, - "uploadBytes": 173116416, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259325952, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000120922, - "uploadBytes": 168396800, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260243456, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000083468, - "uploadBytes": 170266624, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259457024, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000127548, - "uploadBytes": 165366784, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260440064, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.0001285, - "uploadBytes": 164702208, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260505600, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000100856, - "uploadBytes": 174535680, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260177920, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00011458, - "uploadBytes": 167236608, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259260416, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000145016, - "uploadBytes": 172282880, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 260571136, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000125494, - "uploadBytes": 63474688, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 105971712, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000123152, - "uploadBytes": 170739712, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 270991360, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000096382, - "uploadBytes": 168610816, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277217280, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000081786, - "uploadBytes": 161187840, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277151744, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000067465, - "uploadBytes": 165772288, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 276824064, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000093392, - "uploadBytes": 169737216, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 279117824, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000064982, - "uploadBytes": 171257856, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277217280, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000094015, - "uploadBytes": 170255360, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277217280, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000124992, - "uploadBytes": 169556992, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 276561920, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000113901, - "uploadBytes": 168227840, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278200320, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000077515, - "uploadBytes": 171854848, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278790144, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000104088, - "uploadBytes": 173409280, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 279052288, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000134569, - "uploadBytes": 170368000, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277938176, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000081634, - "uploadBytes": 171156480, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278331392, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000122593, - "uploadBytes": 168340480, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278528000, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000106293, - "uploadBytes": 170424320, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 275841024, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000062989, - "uploadBytes": 165040128, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 276824064, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000106889, - "uploadBytes": 174152704, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 276037632, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000091556, - "uploadBytes": 179412992, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 275578880, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000128358, - "uploadBytes": 66437120, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 110821376, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000113226, - "uploadBytes": 163102720, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 275644416, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000062272, - "uploadBytes": 171483136, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277872640, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000120302, - "uploadBytes": 175211520, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 279445504, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000070722, - "uploadBytes": 178883584, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278069248, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000140865, - "uploadBytes": 166786048, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278069248, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000076838, - "uploadBytes": 183546880, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278790144, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00006607, - "uploadBytes": 180190208, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277348352, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00008343, - "uploadBytes": 174355456, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277872640, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000103117, - "uploadBytes": 166617088, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 276365312, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000061368, - "uploadBytes": 180967424, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277741568, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000073697, - "uploadBytes": 165355520, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 279511040, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00005507, - "uploadBytes": 180674560, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278134784, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00007729, - "uploadBytes": 177464320, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278790144, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00006991, - "uploadBytes": 177070080, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 275447808, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00005639, - "uploadBytes": 189595648, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277807104, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000117902, - "uploadBytes": 128435200, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 265093120, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.0000928, - "uploadBytes": 121972736, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 270532608, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000099912, - "uploadBytes": 96294912, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 278069248, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000112752, - "uploadBytes": 65896448, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 93978624, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000099259, - "uploadBytes": 176743424, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 256311296, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00008252, - "uploadBytes": 180257792, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 257490944, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00006473, - "uploadBytes": 174276608, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258342912, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000110424, - "uploadBytes": 174299136, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258408448, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000073813, - "uploadBytes": 176506880, + "type": "intermediary", + "timeSeconds": 1.005, + "uploadBytes": 242548736, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000077214, - "uploadBytes": 182679552, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258342912, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000070516, - "uploadBytes": 179717120, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258342912, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000079037, - "uploadBytes": 178770944, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 257884160, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000085395, - "uploadBytes": 179638272, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258473984, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000073762, - "uploadBytes": 167878656, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 255197184, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000106632, - "uploadBytes": 176811008, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258146304, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000089491, - "uploadBytes": 180021248, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258670592, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000112405, - "uploadBytes": 168284160, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258670592, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000084241, - "uploadBytes": 173161472, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258539520, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000102489, - "uploadBytes": 181812224, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258670592, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000131516, - "uploadBytes": 181519360, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258473984, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000137321, - "uploadBytes": 174062592, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258801664, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000126106, - "uploadBytes": 172778496, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 258801664, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000087588, - "uploadBytes": 58690519, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 90308608, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000114609, - "uploadBytes": 189280256, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 264634368, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000067894, - "uploadBytes": 177576960, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271056896, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000106048, - "uploadBytes": 157729792, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272236544, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000069236, - "uploadBytes": 168554496, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272367616, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000085388, - "uploadBytes": 189460480, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272433152, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000104274, - "uploadBytes": 159610880, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272695296, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000107303, - "uploadBytes": 187173888, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272433152, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000068173, - "uploadBytes": 179322880, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272236544, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000074458, - "uploadBytes": 187658240, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271974400, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000090633, - "uploadBytes": 177509376, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272171008, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000097914, - "uploadBytes": 171032576, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272695296, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000125977, - "uploadBytes": 172192768, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272367616, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000093771, - "uploadBytes": 183231488, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272695296, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000072982, - "uploadBytes": 175571968, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272629760, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000119334, - "uploadBytes": 184763392, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272891904, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000105964, - "uploadBytes": 177058816, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272498688, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000151136, - "uploadBytes": 181654528, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272498688, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000124378, - "uploadBytes": 168374272, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272695296, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000092042, - "uploadBytes": 64833495, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 123863040, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000096315, - "uploadBytes": 175943680, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 265355264, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000106115, - "uploadBytes": 170424320, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 269418496, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000086328, - "uploadBytes": 186892288, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271187968, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000081527, - "uploadBytes": 188897280, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271515648, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000087257, - "uploadBytes": 187737088, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272760832, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000074212, - "uploadBytes": 186531840, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271319040, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000124611, - "uploadBytes": 177115136, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271450112, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000097982, - "uploadBytes": 190586880, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 269811712, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000065441, - "uploadBytes": 181451776, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 270073856, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000095328, - "uploadBytes": 190564352, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 268828672, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000086126, - "uploadBytes": 190879744, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 268500992, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000101581, - "uploadBytes": 175357952, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266665984, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000062756, - "uploadBytes": 188953600, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 269811712, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000130853, - "uploadBytes": 168543232, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 265814016, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000123167, - "uploadBytes": 181496832, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 270663680, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000099826, - "uploadBytes": 178782208, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266928128, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000068183, - "uploadBytes": 186250240, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 267714560, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000105451, - "uploadBytes": 178433024, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 268304384, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000109728, - "uploadBytes": 49304576, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 127991808, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000114964, - "uploadBytes": 172068864, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 268500992, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000113117, - "uploadBytes": 170964992, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272171008, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000118616, - "uploadBytes": 170514432, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 277086208, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000116138, - "uploadBytes": 172023808, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 280035328, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000107437, - "uploadBytes": 171505664, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 286457856, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000079133, - "uploadBytes": 170401792, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 290193408, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000126338, - "uploadBytes": 174603264, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 286130176, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000102227, - "uploadBytes": 174006272, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 288227328, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000080809, - "uploadBytes": 176022528, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 286654464, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000087453, - "uploadBytes": 174479360, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 289996800, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000133463, - "uploadBytes": 171032576, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 292225024, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000076066, - "uploadBytes": 171652096, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 288292864, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000077901, - "uploadBytes": 171978752, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 288620544, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00007505, - "uploadBytes": 172913664, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 287244288, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000097881, - "uploadBytes": 172395520, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 282853376, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000118559, - "uploadBytes": 174851072, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 289931264, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000136075, - "uploadBytes": 170728448, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 291045376, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000080462, - "uploadBytes": 179897344, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 287178752, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.0001484, - "uploadBytes": 54801408, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 85065728, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000115928, - "uploadBytes": 177993728, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 259588096, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000104271, - "uploadBytes": 176214016, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266469376, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000129954, - "uploadBytes": 175346688, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266338304, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000090386, - "uploadBytes": 179863552, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266993664, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00011701, - "uploadBytes": 177137664, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266665984, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000125484, - "uploadBytes": 178140160, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266928128, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000103096, - "uploadBytes": 177498112, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 267059200, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000066288, - "uploadBytes": 177745920, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 265617408, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000124153, - "uploadBytes": 177486848, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266731520, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000091409, - "uploadBytes": 176484352, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266600448, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000103064, - "uploadBytes": 180809728, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266076160, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000122437, - "uploadBytes": 179379200, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 267255808, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000085464, - "uploadBytes": 177790976, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266862592, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000085223, - "uploadBytes": 176675840, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266534912, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000079874, - "uploadBytes": 178635776, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 267321344, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000117063, - "uploadBytes": 185867264, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266665984, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00007965, - "uploadBytes": 181206016, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 267124736, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000092535, - "uploadBytes": 171039744, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266731520, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000120166, - "uploadBytes": 70537216, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 105381888, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000090309, - "uploadBytes": 174310400, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 268500992, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000110949, - "uploadBytes": 178275328, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271777792, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000062237, - "uploadBytes": 171854848, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272629760, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000077127, - "uploadBytes": 165254144, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272760832, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000112773, - "uploadBytes": 168554496, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 273154048, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000080519, - "uploadBytes": 179570688, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272760832, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000077847, - "uploadBytes": 177498112, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272891904, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000126257, - "uploadBytes": 166256640, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271450112, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000070318, - "uploadBytes": 165873664, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 271187968, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000115391, - "uploadBytes": 172249088, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272302080, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000138908, - "uploadBytes": 175921152, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272498688, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000090509, - "uploadBytes": 171359232, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272957440, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000098388, - "uploadBytes": 168745984, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272564224, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000070849, - "uploadBytes": 179345408, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272826368, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000091131, - "uploadBytes": 170863616, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 273022976, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000087296, - "uploadBytes": 171561984, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 267583488, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00011343, - "uploadBytes": 174513152, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 272302080, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000092675, - "uploadBytes": 165276672, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 269090816, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000114376, - "uploadBytes": 63609856, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 96468992, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000072361, - "uploadBytes": 181463040, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 261357568, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000122855, - "uploadBytes": 182093824, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 262733824, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000069967, - "uploadBytes": 182994944, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 264896512, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000098573, - "uploadBytes": 183152640, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266338304, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000055136, - "uploadBytes": 188467200, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 270598144, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000076587, - "uploadBytes": 182141952, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 254279680, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00009874, - "uploadBytes": 184818688, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 262340608, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.00007716, - "uploadBytes": 194608128, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 261423104, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000064374, - "uploadBytes": 187241472, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 261423104, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000127219, - "uploadBytes": 188773376, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 262471680, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000109141, - "uploadBytes": 180021248, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 262864896, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000076944, - "uploadBytes": 175662080, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 261881856, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000114732, - "uploadBytes": 186013696, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266272768, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000116314, - "uploadBytes": 181868544, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266993664, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000066518, - "uploadBytes": 186126336, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 264699904, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000095035, - "uploadBytes": 182274048, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 265027584, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000102547, - "uploadBytes": 180539392, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266469376, "downloadBytes": 0 }, { - "type": "intermediate", - "timeSeconds": 1.000079215, - "uploadBytes": 185337856, + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 266469376, "downloadBytes": 0 } ], - "implementation": "rust-libp2p", - "version": "v0.55", + "implementation": "js-libp2p", + "version": "v2.8-eventtarget", "transportStack": "tcp" - }, + } + ], + "parameters": { + "uploadBytes": 9007199254740991, + "downloadBytes": 0 + } + }, + { + "name": "throughput/download", + "unit": "bit/s", + "results": [ { "result": [ { - "type": "intermediate", - "timeSeconds": 1.000380858, - "uploadBytes": 35324933, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 62586880 }, { - "type": "intermediate", - "timeSeconds": 0.999985143, - "uploadBytes": 70851395, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 235601920 }, { - "type": "intermediate", - "timeSeconds": 1.000247804, - "uploadBytes": 71709930, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265945088 }, { - "type": "intermediate", - "timeSeconds": 1.002953381, - "uploadBytes": 69673381, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 267321344 }, { - "type": "intermediate", - "timeSeconds": 1.000083499, - "uploadBytes": 71712632, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 267124736 }, { - "type": "intermediate", - "timeSeconds": 0.999958051, - "uploadBytes": 73855635, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254083072 }, { - "type": "intermediate", - "timeSeconds": 1.000135251, - "uploadBytes": 72852540, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 249626624 }, { - "type": "intermediate", - "timeSeconds": 1.000221937, - "uploadBytes": 70088392, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 255852544 }, { - "type": "intermediate", - "timeSeconds": 0.999683709, - "uploadBytes": 73498819, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 245235712 }, { - "type": "intermediate", - "timeSeconds": 1.000201138, - "uploadBytes": 67651105, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 251396096 }, { - "type": "intermediate", - "timeSeconds": 1.000272777, - "uploadBytes": 72745920, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262275072 }, { - "type": "intermediate", - "timeSeconds": 1.000098897, - "uploadBytes": 74185725, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 256245760 }, { - "type": "intermediate", - "timeSeconds": 1.00044898, - "uploadBytes": 72081219, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 245760000 }, { - "type": "intermediate", - "timeSeconds": 1.00011149, - "uploadBytes": 69273220, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 251265012 }, { - "type": "intermediate", - "timeSeconds": 0.999762083, - "uploadBytes": 73672864, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 252051468 }, { - "type": "intermediate", - "timeSeconds": 1.000244444, - "uploadBytes": 73019012, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 248119296 }, { - "type": "intermediate", - "timeSeconds": 1.000333475, - "uploadBytes": 70991843, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 251789312 }, { - "type": "intermediate", - "timeSeconds": 1.004609099, - "uploadBytes": 71980289, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 253820928 }, { - "type": "intermediate", - "timeSeconds": 0.999806924, - "uploadBytes": 73008360, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 253952000 }, { - "type": "intermediate", - "timeSeconds": 1.000104069, - "uploadBytes": 33566687, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 38207476 }, { - "type": "intermediate", - "timeSeconds": 1.000437179, - "uploadBytes": 74540374, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 155189248 }, { - "type": "intermediate", - "timeSeconds": 0.99954409, - "uploadBytes": 69794989, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.002, + "uploadBytes": 0, + "downloadBytes": 161611788 }, { - "type": "intermediate", - "timeSeconds": 1.000058707, - "uploadBytes": 70078359, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 168099840 }, { - "type": "intermediate", - "timeSeconds": 1.000149914, - "uploadBytes": 70068254, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 177405952 }, { - "type": "intermediate", - "timeSeconds": 1.00014404, - "uploadBytes": 76047700, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 183566336 }, { - "type": "intermediate", - "timeSeconds": 1.003715732, - "uploadBytes": 67672684, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 187564032 }, { - "type": "intermediate", - "timeSeconds": 1.001214578, - "uploadBytes": 72919056, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 192086016 }, { - "type": "intermediate", - "timeSeconds": 1.000149022, - "uploadBytes": 71987850, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 188284928 }, { - "type": "intermediate", - "timeSeconds": 0.999844975, - "uploadBytes": 73820672, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 118685696 }, { - "type": "intermediate", - "timeSeconds": 1.002047505, - "uploadBytes": 68032866, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 104333312 }, { - "type": "intermediate", - "timeSeconds": 0.999375254, - "uploadBytes": 72848607, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 108593140 }, { - "type": "intermediate", - "timeSeconds": 1.000138173, - "uploadBytes": 72042658, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 108855308 }, { - "type": "intermediate", - "timeSeconds": 1.000066342, - "uploadBytes": 75259222, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 87818240 }, { - "type": "intermediate", - "timeSeconds": 1.000907533, - "uploadBytes": 71027469, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.002, + "uploadBytes": 0, + "downloadBytes": 83689472 }, { - "type": "intermediate", - "timeSeconds": 0.999628708, - "uploadBytes": 69768482, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 86769664 }, { - "type": "intermediate", - "timeSeconds": 1.000128388, - "uploadBytes": 71176383, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.002, + "uploadBytes": 0, + "downloadBytes": 87818240 }, { - "type": "intermediate", - "timeSeconds": 1.00042227, - "uploadBytes": 74751742, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 90570752 }, { - "type": "intermediate", - "timeSeconds": 1.000296655, - "uploadBytes": 72567152, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 92930048 }, { - "type": "intermediate", - "timeSeconds": 1.000186005, - "uploadBytes": 32012706, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 40239104 }, { - "type": "intermediate", - "timeSeconds": 1.000387436, - "uploadBytes": 72866674, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 227606528 }, { - "type": "intermediate", - "timeSeconds": 0.999981046, - "uploadBytes": 69084939, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261357556 }, { - "type": "intermediate", - "timeSeconds": 1.000029742, - "uploadBytes": 69762305, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264437772 }, { - "type": "intermediate", - "timeSeconds": 1.001946542, - "uploadBytes": 71282574, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 269484032 }, { - "type": "intermediate", - "timeSeconds": 1.000239122, - "uploadBytes": 75210971, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 267714560 }, { - "type": "intermediate", - "timeSeconds": 1.000451379, - "uploadBytes": 70926783, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265617396 }, { - "type": "intermediate", - "timeSeconds": 0.99992151, - "uploadBytes": 68531539, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 268959756 }, { - "type": "intermediate", - "timeSeconds": 1.000169522, - "uploadBytes": 71865814, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 267780096 }, { - "type": "intermediate", - "timeSeconds": 1.00007727, - "uploadBytes": 70699841, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264830976 }, { - "type": "intermediate", - "timeSeconds": 1.00025197, - "uploadBytes": 74135639, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 256966656 }, { - "type": "intermediate", - "timeSeconds": 0.999985955, - "uploadBytes": 71989735, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264241152 }, { - "type": "intermediate", - "timeSeconds": 1.000078668, - "uploadBytes": 69508709, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264634368 }, { - "type": "intermediate", - "timeSeconds": 0.99988258, - "uploadBytes": 72843250, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 249167872 }, { - "type": "intermediate", - "timeSeconds": 1.000204956, - "uploadBytes": 72111041, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 269221876 }, { - "type": "intermediate", - "timeSeconds": 0.999870201, - "uploadBytes": 68094006, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258408460 }, { - "type": "intermediate", - "timeSeconds": 1.000203827, - "uploadBytes": 71615085, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 267976704 }, { - "type": "intermediate", - "timeSeconds": 1.000261744, - "uploadBytes": 69997785, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 269484032 }, { - "type": "intermediate", - "timeSeconds": 0.999985521, - "uploadBytes": 73429121, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 268697600 }, { - "type": "intermediate", - "timeSeconds": 1.000138738, - "uploadBytes": 35414065, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 58261504 }, { - "type": "intermediate", - "timeSeconds": 1.000365661, - "uploadBytes": 74386801, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 160759808 }, { - "type": "intermediate", - "timeSeconds": 1.000138216, - "uploadBytes": 72540289, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 170983424 }, { - "type": "intermediate", - "timeSeconds": 1.000441636, - "uploadBytes": 72018756, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 152043520 }, { - "type": "intermediate", - "timeSeconds": 1.000126401, - "uploadBytes": 67692119, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 97648640 }, { - "type": "intermediate", - "timeSeconds": 1.000071833, - "uploadBytes": 72420346, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 95354880 }, { - "type": "intermediate", - "timeSeconds": 0.999731979, - "uploadBytes": 76297077, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 99221504 }, { - "type": "intermediate", - "timeSeconds": 0.999662716, - "uploadBytes": 70709752, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 100532224 }, { - "type": "intermediate", - "timeSeconds": 1.00001666, - "uploadBytes": 70531599, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 102170624 }, { - "type": "intermediate", - "timeSeconds": 0.999874504, - "uploadBytes": 75619010, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 104923136 }, { - "type": "intermediate", - "timeSeconds": 1.000089759, - "uploadBytes": 69842038, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 89784320 }, { - "type": "intermediate", - "timeSeconds": 1.000356103, - "uploadBytes": 70897463, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 77398016 }, { - "type": "intermediate", - "timeSeconds": 1.000181272, - "uploadBytes": 70195200, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 80347136 }, { - "type": "intermediate", - "timeSeconds": 1.00030049, - "uploadBytes": 73669891, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.002, + "uploadBytes": 0, + "downloadBytes": 83427328 }, { - "type": "intermediate", - "timeSeconds": 1.000324848, - "uploadBytes": 73082708, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.002, + "uploadBytes": 0, + "downloadBytes": 85852160 }, { - "type": "intermediate", - "timeSeconds": 1.000307398, - "uploadBytes": 73660643, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 86769664 }, { - "type": "intermediate", - "timeSeconds": 0.999836332, - "uploadBytes": 72038117, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 87621632 }, { - "type": "intermediate", - "timeSeconds": 0.999841841, - "uploadBytes": 73651449, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 88735744 }, { - "type": "intermediate", - "timeSeconds": 0.999842047, - "uploadBytes": 74382172, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 89718784 }, { - "type": "intermediate", - "timeSeconds": 1.000474042, - "uploadBytes": 34236069, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 49414144 }, { - "type": "intermediate", - "timeSeconds": 0.998057575, - "uploadBytes": 71010249, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 214171648 }, { - "type": "intermediate", - "timeSeconds": 1.000050392, - "uploadBytes": 72759378, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 252444672 }, { - "type": "intermediate", - "timeSeconds": 1.002915311, - "uploadBytes": 71645175, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260505600 }, { - "type": "intermediate", - "timeSeconds": 1.000327797, - "uploadBytes": 71065625, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259915776 }, { - "type": "intermediate", - "timeSeconds": 1.000021161, - "uploadBytes": 76251532, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259260416 }, { - "type": "intermediate", - "timeSeconds": 1.000156431, - "uploadBytes": 67333585, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257425408 }, { - "type": "intermediate", - "timeSeconds": 1.000109577, - "uploadBytes": 69564416, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257556468 }, { - "type": "intermediate", - "timeSeconds": 1.000387934, - "uploadBytes": 75050794, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257032204 }, { - "type": "intermediate", - "timeSeconds": 1.00021299, - "uploadBytes": 73946631, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257294336 }, { - "type": "intermediate", - "timeSeconds": 0.999840805, - "uploadBytes": 68858644, - "downloadBytes": 0 - }, - { - "type": "intermediate", - "timeSeconds": 1.000149237, - "uploadBytes": 74863754, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 255852544 }, { - "type": "intermediate", - "timeSeconds": 1.00005989, - "uploadBytes": 71126493, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261029888 }, { - "type": "intermediate", - "timeSeconds": 1.002820611, - "uploadBytes": 72413841, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261292032 }, { - "type": "intermediate", - "timeSeconds": 1.002456859, - "uploadBytes": 73881237, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259719156 }, { - "type": "intermediate", - "timeSeconds": 0.997871981, - "uploadBytes": 72948018, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258670604 }, { - "type": "intermediate", - "timeSeconds": 0.999882636, - "uploadBytes": 73015148, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259260416 }, { - "type": "intermediate", - "timeSeconds": 1.000293016, - "uploadBytes": 69976808, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259719168 }, { - "type": "intermediate", - "timeSeconds": 1.001847172, - "uploadBytes": 73555801, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260571136 }, { - "type": "intermediate", - "timeSeconds": 1.00011776, - "uploadBytes": 33997528, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 252182528 }, { - "type": "intermediate", - "timeSeconds": 0.999328419, - "uploadBytes": 69339670, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 63635456 }, { - "type": "intermediate", - "timeSeconds": 1.000079116, - "uploadBytes": 73748287, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 247201780 }, { - "type": "intermediate", - "timeSeconds": 0.999716588, - "uploadBytes": 67417594, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262733824 }, { - "type": "intermediate", - "timeSeconds": 1.001175235, - "uploadBytes": 69584075, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262995980 }, { - "type": "intermediate", - "timeSeconds": 1.003617975, - "uploadBytes": 72233880, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266665984 }, { - "type": "intermediate", - "timeSeconds": 1.005168381, - "uploadBytes": 71397570, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265355264 }, { - "type": "intermediate", - "timeSeconds": 1.000088068, - "uploadBytes": 69724928, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266272756 }, { - "type": "intermediate", - "timeSeconds": 1.000109951, - "uploadBytes": 67955907, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266403852 }, { - "type": "intermediate", - "timeSeconds": 1.003674207, - "uploadBytes": 72967140, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264372224 }, { - "type": "intermediate", - "timeSeconds": 0.999661945, - "uploadBytes": 72368361, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265551872 }, { - "type": "intermediate", - "timeSeconds": 1.000196598, - "uploadBytes": 68733415, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266207232 }, { - "type": "intermediate", - "timeSeconds": 1.000102944, - "uploadBytes": 72207850, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262209536 }, { - "type": "intermediate", - "timeSeconds": 1.001611626, - "uploadBytes": 69533569, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258473984 }, { - "type": "intermediate", - "timeSeconds": 1.000664428, - "uploadBytes": 70482155, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262733824 }, { - "type": "intermediate", - "timeSeconds": 1.00220986, - "uploadBytes": 68057798, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266862592 }, { - "type": "intermediate", - "timeSeconds": 0.999943083, - "uploadBytes": 70773246, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264830976 }, { - "type": "intermediate", - "timeSeconds": 1.000143051, - "uploadBytes": 73727855, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260898816 }, { - "type": "intermediate", - "timeSeconds": 0.999664014, - "uploadBytes": 73045948, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258998272 }, { - "type": "intermediate", - "timeSeconds": 1.000613571, - "uploadBytes": 34188730, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259260416 }, { - "type": "intermediate", - "timeSeconds": 1.01741187, - "uploadBytes": 72722840, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 33161216 }, { - "type": "intermediate", - "timeSeconds": 0.989040429, - "uploadBytes": 72164122, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 211681280 }, { - "type": "intermediate", - "timeSeconds": 1.000217836, - "uploadBytes": 73006842, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259129344 }, { - "type": "intermediate", - "timeSeconds": 1.005796394, - "uploadBytes": 71108611, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258146304 }, { - "type": "intermediate", - "timeSeconds": 1.000074775, - "uploadBytes": 76262435, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259784704 }, { - "type": "intermediate", - "timeSeconds": 1.000092028, - "uploadBytes": 72016356, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260898816 }, { - "type": "intermediate", - "timeSeconds": 1.000026982, - "uploadBytes": 70912634, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261226496 }, { - "type": "intermediate", - "timeSeconds": 1.003801235, - "uploadBytes": 70703697, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261357568 }, { - "type": "intermediate", - "timeSeconds": 1.000091369, - "uploadBytes": 74298929, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 256704512 }, { - "type": "intermediate", - "timeSeconds": 1.003643934, - "uploadBytes": 67096669, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258211840 }, { - "type": "intermediate", - "timeSeconds": 1.000293971, - "uploadBytes": 72562983, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261292032 }, { - "type": "intermediate", - "timeSeconds": 1.000432224, - "uploadBytes": 73598480, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261095412 }, { - "type": "intermediate", - "timeSeconds": 1.000149506, - "uploadBytes": 72438899, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260898828 }, { - "type": "intermediate", - "timeSeconds": 1.000217524, - "uploadBytes": 70219494, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258605056 }, { - "type": "intermediate", - "timeSeconds": 0.999936151, - "uploadBytes": 71081863, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254345216 }, { - "type": "intermediate", - "timeSeconds": 0.99995684, - "uploadBytes": 71027196, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259981312 }, { - "type": "intermediate", - "timeSeconds": 1.000231128, - "uploadBytes": 74511340, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260308992 }, { - "type": "intermediate", - "timeSeconds": 1.003068525, - "uploadBytes": 69496955, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257032192 }, { - "type": "intermediate", - "timeSeconds": 1.000202824, - "uploadBytes": 30881032, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 245628928 }, { - "type": "intermediate", - "timeSeconds": 1.000348201, - "uploadBytes": 70142642, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 70320128 }, { - "type": "intermediate", - "timeSeconds": 0.999959852, - "uploadBytes": 70342474, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 252444672 }, { - "type": "intermediate", - "timeSeconds": 1.004551495, - "uploadBytes": 71347897, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265748480 }, { - "type": "intermediate", - "timeSeconds": 1.000332988, - "uploadBytes": 70806445, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266469364 }, { - "type": "intermediate", - "timeSeconds": 1.00065122, - "uploadBytes": 70280393, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266272780 }, { - "type": "intermediate", - "timeSeconds": 1.00024806, - "uploadBytes": 71555936, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266207232 }, { - "type": "intermediate", - "timeSeconds": 1.000370738, - "uploadBytes": 68392845, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264568832 }, { - "type": "intermediate", - "timeSeconds": 1.000066097, - "uploadBytes": 72518264, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265093120 }, { - "type": "intermediate", - "timeSeconds": 1.006247743, - "uploadBytes": 70374516, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 241106944 }, { - "type": "intermediate", - "timeSeconds": 1.00029709, - "uploadBytes": 67688121, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257818624 }, { - "type": "intermediate", - "timeSeconds": 0.99977783, - "uploadBytes": 70595137, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 267452416 }, { - "type": "intermediate", - "timeSeconds": 0.999667549, - "uploadBytes": 71948452, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 268959744 }, { - "type": "intermediate", - "timeSeconds": 1.009249331, - "uploadBytes": 70193708, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265158656 }, { - "type": "intermediate", - "timeSeconds": 1.000696699, - "uploadBytes": 70654845, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260440064 }, { - "type": "intermediate", - "timeSeconds": 0.999670443, - "uploadBytes": 70479988, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258408448 }, { - "type": "intermediate", - "timeSeconds": 1.000066348, - "uploadBytes": 70338491, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 252313600 }, { - "type": "intermediate", - "timeSeconds": 1.000260029, - "uploadBytes": 71071509, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257753088 }, { - "type": "intermediate", - "timeSeconds": 1.000404352, - "uploadBytes": 72207364, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262668288 }, { - "type": "intermediate", - "timeSeconds": 1.000350612, - "uploadBytes": 33439408, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264568832 }, { - "type": "intermediate", - "timeSeconds": 1.00086898, - "uploadBytes": 69245867, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 61603840 }, { - "type": "intermediate", - "timeSeconds": 1.000229028, - "uploadBytes": 70702634, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 231735296 }, { - "type": "intermediate", - "timeSeconds": 1.000153688, - "uploadBytes": 70886681, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 274857984 }, { - "type": "intermediate", - "timeSeconds": 1.000186114, - "uploadBytes": 74272594, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254017536 }, { - "type": "intermediate", - "timeSeconds": 1.000336406, - "uploadBytes": 72036701, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261029888 }, { - "type": "intermediate", - "timeSeconds": 0.999690976, - "uploadBytes": 74491396, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275644416 }, { - "type": "intermediate", - "timeSeconds": 0.999956266, - "uploadBytes": 67609190, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275054592 }, { - "type": "intermediate", - "timeSeconds": 1.00011116, - "uploadBytes": 73667435, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265158656 }, { - "type": "intermediate", - "timeSeconds": 1.004013269, - "uploadBytes": 68879513, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257490944 }, { - "type": "intermediate", - "timeSeconds": 1.000136336, - "uploadBytes": 74339253, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263258112 }, { - "type": "intermediate", - "timeSeconds": 0.999684267, - "uploadBytes": 70784222, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 271581184 }, { - "type": "intermediate", - "timeSeconds": 1.000315332, - "uploadBytes": 67218769, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 268697588 }, { - "type": "intermediate", - "timeSeconds": 1.000301096, - "uploadBytes": 69433344, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266338316 }, { - "type": "intermediate", - "timeSeconds": 1.012685563, - "uploadBytes": 74666076, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275447808 }, { - "type": "intermediate", - "timeSeconds": 1.000110795, - "uploadBytes": 73078548, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273874944 }, { - "type": "intermediate", - "timeSeconds": 0.999718253, - "uploadBytes": 69317319, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 274268148 }, { - "type": "intermediate", - "timeSeconds": 1.008258815, - "uploadBytes": 72751889, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273743884 }, { - "type": "intermediate", - "timeSeconds": 0.998727858, - "uploadBytes": 71947295, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273022976 }, { - "type": "intermediate", - "timeSeconds": 1.000402051, - "uploadBytes": 34920280, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 267780096 }, { - "type": "intermediate", - "timeSeconds": 1.000269193, - "uploadBytes": 70050473, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 49283072 }, { - "type": "intermediate", - "timeSeconds": 0.998855493, - "uploadBytes": 70140778, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 208207872 }, { - "type": "intermediate", - "timeSeconds": 1.000091193, - "uploadBytes": 71515772, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 220594176 }, { - "type": "intermediate", - "timeSeconds": 1.000588448, - "uploadBytes": 73175101, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 231211008 }, { - "type": "intermediate", - "timeSeconds": 1.000073186, - "uploadBytes": 71461833, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 239796224 }, { - "type": "intermediate", - "timeSeconds": 1.000876005, - "uploadBytes": 66185056, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 246415348 }, { - "type": "intermediate", - "timeSeconds": 0.999746598, - "uploadBytes": 73775668, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 253493260 }, { - "type": "intermediate", - "timeSeconds": 1.000223656, - "uploadBytes": 71942474, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257884160 }, { - "type": "intermediate", - "timeSeconds": 1.000205033, - "uploadBytes": 71708580, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 249298944 }, { - "type": "intermediate", - "timeSeconds": 1.000418155, - "uploadBytes": 67300137, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260112384 }, { - "type": "intermediate", - "timeSeconds": 1.000260496, - "uploadBytes": 72317841, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 249626624 }, { - "type": "intermediate", - "timeSeconds": 1.000071711, - "uploadBytes": 74178591, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262012916 }, { - "type": "intermediate", - "timeSeconds": 1.000287942, - "uploadBytes": 68568848, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 251461644 }, { - "type": "intermediate", - "timeSeconds": 1.000272108, - "uploadBytes": 73602828, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257294336 }, { - "type": "intermediate", - "timeSeconds": 1.000077613, - "uploadBytes": 71926123, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259719168 }, { - "type": "intermediate", - "timeSeconds": 1.001879342, - "uploadBytes": 69837812, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260571136 }, { - "type": "intermediate", - "timeSeconds": 1.000109806, - "uploadBytes": 73989678, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260308992 }, { - "type": "intermediate", - "timeSeconds": 0.999910124, - "uploadBytes": 71035290, - "downloadBytes": 0 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259850240 + }, + { + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 256507904 } ], - "implementation": "rust-libp2p", - "version": "v0.55", - "transportStack": "quic-v1" + "implementation": "js-libp2p", + "version": "v2.8", + "transportStack": "tcp" }, { "result": [ { "type": "intermediary", - "timeSeconds": 1.000041672, - "uploadBytes": 149356544, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 67502080 }, { "type": "intermediary", - "timeSeconds": 1.000013537, - "uploadBytes": 662011904, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 236257280 }, { "type": "intermediary", - "timeSeconds": 1.000005046, - "uploadBytes": 553615360, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263913472 }, { "type": "intermediary", - "timeSeconds": 1.00004604, - "uploadBytes": 634257408, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263979008 }, { "type": "intermediary", - "timeSeconds": 1.000054431, - "uploadBytes": 568623104, - "downloadBytes": 0 + "timeSeconds": 1.002, + "uploadBytes": 0, + "downloadBytes": 261881856 }, { "type": "intermediary", - "timeSeconds": 1.000025653, - "uploadBytes": 634290176, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260046848 }, { "type": "intermediary", - "timeSeconds": 1.000013545, - "uploadBytes": 569081856, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262078464 }, { "type": "intermediary", - "timeSeconds": 1.000006914, - "uploadBytes": 607387648, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264175616 }, { "type": "intermediary", - "timeSeconds": 1.016859534, - "uploadBytes": 557056000, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261488640 }, { "type": "intermediary", - "timeSeconds": 1.000035272, - "uploadBytes": 614170624, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261226496 }, { "type": "intermediary", - "timeSeconds": 1.048179538, - "uploadBytes": 607748096, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262471680 }, { "type": "intermediary", - "timeSeconds": 1.085875948, - "uploadBytes": 647757824, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263258112 }, { "type": "intermediary", - "timeSeconds": 1.000015284, - "uploadBytes": 638713856, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264568832 }, { "type": "intermediary", - "timeSeconds": 1.000024302, - "uploadBytes": 557121536, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264896512 }, { "type": "intermediary", - "timeSeconds": 1.059531751, - "uploadBytes": 629309440, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260308992 }, { "type": "intermediary", - "timeSeconds": 1.000007435, - "uploadBytes": 614236160, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258080768 }, { "type": "intermediary", - "timeSeconds": 1.000057952, - "uploadBytes": 617250816, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264437760 }, { "type": "intermediary", - "timeSeconds": 1.005959315, - "uploadBytes": 561872896, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263520256 }, { "type": "intermediary", - "timeSeconds": 1.000021685, - "uploadBytes": 599949312, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263389184 }, { "type": "intermediary", - "timeSeconds": 1.000017765, - "uploadBytes": 117145600, - "downloadBytes": 0 - }, + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 78839808 + }, { "type": "intermediary", - "timeSeconds": 1.000032303, - "uploadBytes": 647233536, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 251592704 }, { "type": "intermediary", - "timeSeconds": 1.0799641, - "uploadBytes": 637829120, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254345216 }, { "type": "intermediary", - "timeSeconds": 1.092699773, - "uploadBytes": 651853824, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262537216 }, { "type": "intermediary", - "timeSeconds": 1.000009595, - "uploadBytes": 634978304, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265486336 }, { "type": "intermediary", - "timeSeconds": 1.073040096, - "uploadBytes": 601587712, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262471680 }, { "type": "intermediary", - "timeSeconds": 1.100964769, - "uploadBytes": 656900096, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262471680 }, { "type": "intermediary", - "timeSeconds": 1.1063690880000001, - "uploadBytes": 659914752, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261423104 }, { "type": "intermediary", - "timeSeconds": 1.000050101, - "uploadBytes": 654082048, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262799360 }, { "type": "intermediary", - "timeSeconds": 1.000016234, - "uploadBytes": 550535168, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260964352 }, { "type": "intermediary", - "timeSeconds": 1.0673983360000001, - "uploadBytes": 625311744, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257359872 }, { "type": "intermediary", - "timeSeconds": 1.0814052140000001, - "uploadBytes": 645136384, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266928128 }, { "type": "intermediary", - "timeSeconds": 1.080007648, - "uploadBytes": 644382720, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260898816 }, { "type": "intermediary", - "timeSeconds": 1.078912968, - "uploadBytes": 643596288, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259522560 }, { "type": "intermediary", - "timeSeconds": 1.096405476, - "uploadBytes": 654114816, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262144000 }, { "type": "intermediary", - "timeSeconds": 1.068462599, - "uploadBytes": 637337600, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259784704 }, { "type": "intermediary", - "timeSeconds": 1.073615443, - "uploadBytes": 640483328, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264962048 }, { "type": "intermediary", - "timeSeconds": 1.072092801, - "uploadBytes": 639598592, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259194880 }, { "type": "intermediary", - "timeSeconds": 1.000008654, - "uploadBytes": 174850048, - "downloadBytes": 0 + "timeSeconds": 1.003, + "uploadBytes": 0, + "downloadBytes": 260308992 }, { "type": "intermediary", - "timeSeconds": 1.000008961, - "uploadBytes": 654737408, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 83427328 }, { "type": "intermediary", - "timeSeconds": 1.000023023, - "uploadBytes": 608796672, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 238354432 }, { "type": "intermediary", - "timeSeconds": 1.0889124510000001, - "uploadBytes": 593788928, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 255524864 }, { "type": "intermediary", - "timeSeconds": 1.06139288, - "uploadBytes": 633143296, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 253820928 }, { "type": "intermediary", - "timeSeconds": 1.000005236, - "uploadBytes": 609779712, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258080768 }, { "type": "intermediary", - "timeSeconds": 1.000000929, - "uploadBytes": 599359488, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 256835584 }, { "type": "intermediary", - "timeSeconds": 1.000018907, - "uploadBytes": 619544576, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 253362176 }, { "type": "intermediary", - "timeSeconds": 1.000021161, - "uploadBytes": 612728832, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254803968 }, { "type": "intermediary", - "timeSeconds": 1.000010884, - "uploadBytes": 550109184, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 255459328 }, { "type": "intermediary", - "timeSeconds": 1.014282311, - "uploadBytes": 596443136, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 253362176 }, { "type": "intermediary", - "timeSeconds": 1.028702211, - "uploadBytes": 613679104, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 256901120 }, { "type": "intermediary", - "timeSeconds": 1.048821959, - "uploadBytes": 625737728, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 253362176 }, { "type": "intermediary", - "timeSeconds": 1.084949436, - "uploadBytes": 647233536, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 252641280 }, { "type": "intermediary", - "timeSeconds": 1.060080359, - "uploadBytes": 632324096, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254214144 }, { "type": "intermediary", - "timeSeconds": 1.033089656, - "uploadBytes": 616333312, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 251330560 }, { "type": "intermediary", - "timeSeconds": 1.00000686, - "uploadBytes": 643858432, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 255655936 }, { "type": "intermediary", - "timeSeconds": 1.028839307, - "uploadBytes": 566460416, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254279680 }, { "type": "intermediary", - "timeSeconds": 1.000005257, - "uploadBytes": 633765888, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 254607360 }, { "type": "intermediary", - "timeSeconds": 1.000021014, - "uploadBytes": 182616064, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 256049140 }, { "type": "intermediary", - "timeSeconds": 1.000015298, - "uploadBytes": 628359168, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 104005632 }, { "type": "intermediary", - "timeSeconds": 1.087862553, - "uploadBytes": 625442816, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 274923520 }, { "type": "intermediary", - "timeSeconds": 1.000018937, - "uploadBytes": 654737408, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264306688 }, { "type": "intermediary", - "timeSeconds": 1.000012286, - "uploadBytes": 543916032, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273809408 }, { "type": "intermediary", - "timeSeconds": 1.000044273, - "uploadBytes": 633896960, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 266797056 }, { "type": "intermediary", - "timeSeconds": 1.082870714, - "uploadBytes": 603226112, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275447808 }, { "type": "intermediary", - "timeSeconds": 1.072987548, - "uploadBytes": 640024576, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275513344 }, { "type": "intermediary", - "timeSeconds": 1.000017394, - "uploadBytes": 636878848, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 276430848 }, { "type": "intermediary", - "timeSeconds": 1.075013594, - "uploadBytes": 600997888, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 268500992 }, { "type": "intermediary", - "timeSeconds": 1.000001909, - "uploadBytes": 625672192, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 271187968 }, { "type": "intermediary", - "timeSeconds": 1.000011838, - "uploadBytes": 621805568, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 277676032 }, { "type": "intermediary", - "timeSeconds": 1.081398761, - "uploadBytes": 590708736, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 276955136 }, { "type": "intermediary", - "timeSeconds": 1.000041916, - "uploadBytes": 625278976, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272433152 }, { "type": "intermediary", - "timeSeconds": 1.00004892, - "uploadBytes": 620986368, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 276430848 }, { "type": "intermediary", - "timeSeconds": 1.049485305, - "uploadBytes": 573014016, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 268697600 }, { "type": "intermediary", - "timeSeconds": 1.071524156, - "uploadBytes": 639238144, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 277938176 }, { "type": "intermediary", - "timeSeconds": 1.064098862, - "uploadBytes": 634814464, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 270729216 }, { "type": "intermediary", - "timeSeconds": 1.000026586, - "uploadBytes": 611811328, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273678336 }, { "type": "intermediary", - "timeSeconds": 1.000013287, - "uploadBytes": 174915584, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272367616 }, { "type": "intermediary", - "timeSeconds": 1.070973683, - "uploadBytes": 651657216, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 77856768 }, { "type": "intermediary", - "timeSeconds": 1.000003495, - "uploadBytes": 646643712, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 247529472 }, { "type": "intermediary", - "timeSeconds": 1.000001778, - "uploadBytes": 575242240, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 257884160 }, { "type": "intermediary", - "timeSeconds": 1.028257289, - "uploadBytes": 584843264, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258867200 }, { "type": "intermediary", - "timeSeconds": 1.000032797, - "uploadBytes": 636649472, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259981312 }, { "type": "intermediary", - "timeSeconds": 1.038623779, - "uploadBytes": 579469312, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259981312 }, { "type": "intermediary", - "timeSeconds": 1.000011016, - "uploadBytes": 650706944, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258867200 }, { "type": "intermediary", - "timeSeconds": 1.00002234, - "uploadBytes": 553418752, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259981312 }, { "type": "intermediary", - "timeSeconds": 1.000046255, - "uploadBytes": 640811008, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258998272 }, { "type": "intermediary", - "timeSeconds": 1.002129392, - "uploadBytes": 542539776, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259194880 }, { "type": "intermediary", - "timeSeconds": 1.000014982, - "uploadBytes": 654966784, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260374528 }, { "type": "intermediary", - "timeSeconds": 1.000002546, - "uploadBytes": 538968064, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260046848 }, { "type": "intermediary", - "timeSeconds": 1.000033807, - "uploadBytes": 637206528, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259981312 }, { "type": "intermediary", - "timeSeconds": 1.058845153, - "uploadBytes": 590086144, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260243456 }, { "type": "intermediary", - "timeSeconds": 1.000018295, - "uploadBytes": 625967104, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260308992 }, { "type": "intermediary", - "timeSeconds": 1.000022363, - "uploadBytes": 622297088, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259850240 }, { "type": "intermediary", - "timeSeconds": 1.011460891, - "uploadBytes": 548536320, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259784704 }, { "type": "intermediary", - "timeSeconds": 1.00407337, - "uploadBytes": 598900736, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259653632 }, { "type": "intermediary", - "timeSeconds": 1.000014265, - "uploadBytes": 162267136, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259784704 }, { "type": "intermediary", - "timeSeconds": 1.038902128, - "uploadBytes": 645136384, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 60882944 }, { "type": "intermediary", - "timeSeconds": 1.047332293, - "uploadBytes": 624754688, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 241434624 }, { "type": "intermediary", - "timeSeconds": 1.050095814, - "uploadBytes": 626393088, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262733824 }, { "type": "intermediary", - "timeSeconds": 1.055242054, - "uploadBytes": 629080064, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259981312 }, { "type": "intermediary", - "timeSeconds": 1.000001396, - "uploadBytes": 507740160, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261947392 }, { "type": "intermediary", - "timeSeconds": 1.000001439, - "uploadBytes": 424542208, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261619712 }, { "type": "intermediary", - "timeSeconds": 1.000023939, - "uploadBytes": 471924736, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263389184 }, { "type": "intermediary", - "timeSeconds": 1.000023846, - "uploadBytes": 472678400, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263258112 }, { "type": "intermediary", - "timeSeconds": 1.137272375, - "uploadBytes": 481525760, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262275072 }, { "type": "intermediary", - "timeSeconds": 1.000015602, - "uploadBytes": 492339200, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261816320 }, { "type": "intermediary", - "timeSeconds": 1.000020689, - "uploadBytes": 497025024, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262799360 }, { "type": "intermediary", - "timeSeconds": 1.000006106, - "uploadBytes": 493256704, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263061504 }, { "type": "intermediary", - "timeSeconds": 1.000019249, - "uploadBytes": 402325504, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262078464 }, { "type": "intermediary", - "timeSeconds": 1.000003862, - "uploadBytes": 304349184, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 259063808 }, { "type": "intermediary", - "timeSeconds": 1.025198887, - "uploadBytes": 362774528, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258539520 }, { "type": "intermediary", - "timeSeconds": 1.012242365, - "uploadBytes": 375980032, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 261816320 }, { "type": "intermediary", - "timeSeconds": 1.001343586, - "uploadBytes": 381616128, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263651328 }, { "type": "intermediary", - "timeSeconds": 1.000068066, - "uploadBytes": 416350208, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 262537216 }, { "type": "intermediary", - "timeSeconds": 1.000037128, - "uploadBytes": 201293824, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 258539520 }, { "type": "intermediary", - "timeSeconds": 1.000018167, - "uploadBytes": 657948672, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 88932352 }, { "type": "intermediary", - "timeSeconds": 1.004824137, - "uploadBytes": 545161216, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 260505600 }, { "type": "intermediary", - "timeSeconds": 1.095398168, - "uploadBytes": 653524992, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272236544 }, { "type": "intermediary", - "timeSeconds": 1.000001752, - "uploadBytes": 660832256, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272629760 }, { "type": "intermediary", - "timeSeconds": 1.00000315, - "uploadBytes": 570228736, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273219584 }, { "type": "intermediary", - "timeSeconds": 1.000011749, - "uploadBytes": 580026368, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272564224 }, { "type": "intermediary", - "timeSeconds": 1.018854598, - "uploadBytes": 586448896, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273350656 }, { "type": "intermediary", - "timeSeconds": 1.10880153, - "uploadBytes": 661323776, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272629760 }, { "type": "intermediary", - "timeSeconds": 1.090125019, - "uploadBytes": 650346496, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272367616 }, { "type": "intermediary", - "timeSeconds": 1.091165383, - "uploadBytes": 650870784, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272564224 }, { "type": "intermediary", - "timeSeconds": 1.000002953, - "uploadBytes": 626950144, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273154048 }, { "type": "intermediary", - "timeSeconds": 1.062873132, - "uploadBytes": 603815936, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 271515648 }, { "type": "intermediary", - "timeSeconds": 1.038234331, - "uploadBytes": 619216896, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272629748 }, { "type": "intermediary", - "timeSeconds": 1.000010276, - "uploadBytes": 656211968, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 270598156 }, { "type": "intermediary", - "timeSeconds": 1.000019211, - "uploadBytes": 541786112, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272039936 }, { "type": "intermediary", - "timeSeconds": 1.104682339, - "uploadBytes": 654180352, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272826368 }, { "type": "intermediary", - "timeSeconds": 1.000015319, - "uploadBytes": 652804096, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 271974388 }, { "type": "intermediary", - "timeSeconds": 1.040735393, - "uploadBytes": 564723712, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 272105484 }, { "type": "intermediary", - "timeSeconds": 1.01275321, - "uploadBytes": 15794176, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 273678336 }, { "type": "intermediary", - "timeSeconds": 1.000029074, - "uploadBytes": 599392256, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 69074944 }, { "type": "intermediary", - "timeSeconds": 1.016520105, - "uploadBytes": 498073600, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 249167872 }, { "type": "intermediary", - "timeSeconds": 1.064917617, - "uploadBytes": 489357312, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263323648 }, { "type": "intermediary", - "timeSeconds": 1.019807731, - "uploadBytes": 489291776, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265551872 }, { "type": "intermediary", - "timeSeconds": 1.051521638, - "uploadBytes": 522092544, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264699904 }, { "type": "intermediary", - "timeSeconds": 1.053968042, - "uploadBytes": 540934144, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264699904 }, { "type": "intermediary", - "timeSeconds": 1.082624155, - "uploadBytes": 487849984, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265224192 }, { "type": "intermediary", - "timeSeconds": 1.091763643, - "uploadBytes": 416645120, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265158656 }, { "type": "intermediary", - "timeSeconds": 1.000038163, - "uploadBytes": 429588480, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264175616 }, { "type": "intermediary", - "timeSeconds": 1.05314624, - "uploadBytes": 382795776, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263913472 }, { "type": "intermediary", - "timeSeconds": 1.076118479, - "uploadBytes": 440172544, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 263585792 }, { "type": "intermediary", - "timeSeconds": 1.075276786, - "uploadBytes": 448036864, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264699904 }, { "type": "intermediary", - "timeSeconds": 1.092756695, - "uploadBytes": 459341824, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265158656 }, { "type": "intermediary", - "timeSeconds": 1.083278869, - "uploadBytes": 463142912, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264699904 }, { "type": "intermediary", - "timeSeconds": 1.086077572, - "uploadBytes": 470253568, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264962048 }, { "type": "intermediary", - "timeSeconds": 1.05745556, - "uploadBytes": 462716928, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265224192 }, { "type": "intermediary", - "timeSeconds": 1.07512505, - "uploadBytes": 473300992, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265158656 }, { "type": "intermediary", - "timeSeconds": 1.008605132, - "uploadBytes": 59834368, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 265289728 }, { "type": "intermediary", - "timeSeconds": 1.057772121, - "uploadBytes": 700645376, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 264830976 }, { "type": "intermediary", - "timeSeconds": 1.000014403, - "uploadBytes": 630194176, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 55771136 }, { "type": "intermediary", - "timeSeconds": 1.050927178, - "uploadBytes": 465502208, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 245825536 }, { "type": "intermediary", - "timeSeconds": 1.00000113, - "uploadBytes": 469139456, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 287375360 }, { "type": "intermediary", - "timeSeconds": 1.000004072, - "uploadBytes": 475987968, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 288882688 }, { "type": "intermediary", - "timeSeconds": 1.000013581, - "uploadBytes": 468320256, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 290324480 }, { "type": "intermediary", - "timeSeconds": 1.032959471, - "uploadBytes": 333348864, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 288620544 }, { "type": "intermediary", - "timeSeconds": 1.058885459, - "uploadBytes": 366346240, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 288423936 }, { "type": "intermediary", - "timeSeconds": 1.038937601, - "uploadBytes": 368115712, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 286654464 }, { "type": "intermediary", - "timeSeconds": 1.039537958, - "uploadBytes": 376766464, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 288751616 }, { "type": "intermediary", - "timeSeconds": 1.012077691, - "uploadBytes": 374145024, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 282525696 }, { "type": "intermediary", - "timeSeconds": 1.005233014, - "uploadBytes": 376832000, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 291635200 }, { "type": "intermediary", - "timeSeconds": 1.000132872, - "uploadBytes": 378896384, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 277348352 }, { "type": "intermediary", - "timeSeconds": 1.21168711, - "uploadBytes": 331612160, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 282329088 }, { "type": "intermediary", - "timeSeconds": 1.183953676, - "uploadBytes": 334921728, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 291569664 }, { "type": "intermediary", - "timeSeconds": 1.203468672, - "uploadBytes": 334528512, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 274268160 }, { "type": "intermediary", - "timeSeconds": 1.090155708, - "uploadBytes": 231112704, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 283312128 }, { "type": "intermediary", - "timeSeconds": 1.000048859, - "uploadBytes": 154796032, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 277741568 }, { "type": "intermediary", - "timeSeconds": 1.000005605, - "uploadBytes": 636813312, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 283901952 }, { "type": "intermediary", - "timeSeconds": 1.008178303, - "uploadBytes": 569704448, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275447808 }, { "type": "intermediary", - "timeSeconds": 1.086373556, - "uploadBytes": 647954432, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 71106560 }, { "type": "intermediary", - "timeSeconds": 1.067989389, - "uploadBytes": 637206528, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 250347520 }, { "type": "intermediary", - "timeSeconds": 1.039648021, - "uploadBytes": 620331008, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 278986752 }, { "type": "intermediary", - "timeSeconds": 1.000010172, - "uploadBytes": 602865664, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 278200320 }, { "type": "intermediary", - "timeSeconds": 1.000009885, - "uploadBytes": 602832896, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 284098560 }, { "type": "intermediary", - "timeSeconds": 1.000038236, - "uploadBytes": 607256576, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 278790144 }, { "type": "intermediary", - "timeSeconds": 1.000027511, - "uploadBytes": 605290496, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 284622848 }, { "type": "intermediary", - "timeSeconds": 1.0000455, - "uploadBytes": 603062272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000012279, - "uploadBytes": 603815936, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003355, - "uploadBytes": 601227264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000032838, - "uploadBytes": 583598080, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019007, - "uploadBytes": 574291968, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001727551, - "uploadBytes": 582189056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019553, - "uploadBytes": 600539136, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019789, - "uploadBytes": 603881472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010693, - "uploadBytes": 622723072, - "downloadBytes": 0 - } - ], - "implementation": "https", - "version": "v0.1", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.01199494, - "uploadBytes": 16777216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000065455, - "uploadBytes": 113639424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066705784, - "uploadBytes": 112852992, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.057719602, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000095925, - "uploadBytes": 115277824, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.027595582, - "uploadBytes": 94437376, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000084173, - "uploadBytes": 114229248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067650453, - "uploadBytes": 112263168, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000038648, - "uploadBytes": 116457472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.064347013, - "uploadBytes": 110034944, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000071749, - "uploadBytes": 114425856, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.065385992, - "uploadBytes": 112066560, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.11196941, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.040425736, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.036436964, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.034291685, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.033868946, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.031642662, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.031765902, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000041535, - "uploadBytes": 24051712, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053919194, - "uploadBytes": 110166016, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06237445, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.056472752, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06366365, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.056139969, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061258226, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061028884, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06337431, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.055462115, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059451034, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063058783, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.054195249, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059568761, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059952834, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062811254, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059154431, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063360266, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.047677988, - "uploadBytes": 41943040, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.057655993, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059924929, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061454424, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059648264, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059041673, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.060963407, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059299932, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.057881298, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061590437, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.058186481, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059774322, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.057511205, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059977105, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06085538, - "uploadBytes": 117440512, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 284688384 }, { "type": "intermediary", - "timeSeconds": 1.057815431, - "uploadBytes": 117440512, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 281214976 }, { "type": "intermediary", - "timeSeconds": 1.059430255, - "uploadBytes": 117440512, - "downloadBytes": 0 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275972096 }, { "type": "intermediary", - "timeSeconds": 1.058259414, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.006958826, - "uploadBytes": 8388608, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.043654453, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017537, - "uploadBytes": 113639424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063048928, - "uploadBytes": 112852992, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000038141, - "uploadBytes": 112787456, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066444806, - "uploadBytes": 113704960, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066744658, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067398927, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067755954, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06793163, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000121121, - "uploadBytes": 117047296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.058511953, - "uploadBytes": 109445120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.0669577590000001, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011539, - "uploadBytes": 116719616, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.060267333, - "uploadBytes": 109772800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000144379, - "uploadBytes": 115736576, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.060861142, - "uploadBytes": 110755840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.065203736, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.042785026, - "uploadBytes": 33554432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000026379, - "uploadBytes": 114622464, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027422, - "uploadBytes": 110821376, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067182803, - "uploadBytes": 110100480, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000076387, - "uploadBytes": 114360320, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066107679, - "uploadBytes": 112132096, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000119554, - "uploadBytes": 114163712, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000098503, - "uploadBytes": 107675648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027427, - "uploadBytes": 108724224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000092972, - "uploadBytes": 111017984, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000037889, - "uploadBytes": 107675648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009857, - "uploadBytes": 109772800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000063973, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066697401, - "uploadBytes": 112590848, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000012692, - "uploadBytes": 112721920, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000612086, - "uploadBytes": 105381888, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009011, - "uploadBytes": 113246208, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000056344, - "uploadBytes": 108593152, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00003357, - "uploadBytes": 113639424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.118464242, - "uploadBytes": 16777216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053335484, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.052480447, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.056907014, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.054811466, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053195225, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.051951124, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.051066791, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.056835228, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053501187, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.056753032, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.055090801, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.051188465, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.050535223, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.048280731, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.049431246, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.050691251, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053963161, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.09603188, - "uploadBytes": 16777216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.058691262, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.04138572, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.183525846, - "uploadBytes": 58720256, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.168192131, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.162416656, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.158436406, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.15526028, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.152156958, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.153464925, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.151871263, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.15156634, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.152921391, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.152673047, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.152942374, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.154604377, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.028539331, - "uploadBytes": 41943040, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.008324774, - "uploadBytes": 16777216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062494668, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063827051, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.060132696, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06543992, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062520058, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.064930032, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063108743, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067593062, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.065035585, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000119893, - "uploadBytes": 117047296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.054549372, - "uploadBytes": 109445120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062421858, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066818395, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.068795636, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066282299, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.064813758, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.064390189, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.025315003, - "uploadBytes": 16777216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003719031, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005002306, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005586038, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002606432, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004126833, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003916765, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003293095, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004526685, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002376601, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00210714, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003575599, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004091443, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004788812, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005599752, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002133959, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005931333, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003615811, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004330549, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00090017, - "uploadBytes": 16777216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06156341, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062905787, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.050022847, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061563909, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.060723717, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059268256, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063977113, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062787743, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063159997, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06338975, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066496637, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062814611, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.060148453, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061252485, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063907913, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.058040908, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062843383, - "uploadBytes": 117440512, - "downloadBytes": 0 - } - ], - "implementation": "go-libp2p", - "version": "v0.41", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.009545779, - "uploadBytes": 50855936, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000048343, - "uploadBytes": 72876032, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000054407, - "uploadBytes": 71958528, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00503593, - "uploadBytes": 73203712, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000083124, - "uploadBytes": 72941568, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00214767, - "uploadBytes": 72679424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000241159, - "uploadBytes": 73924608, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000169336, - "uploadBytes": 73007104, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001627367, - "uploadBytes": 74186752, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000483384, - "uploadBytes": 73793536, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000813707, - "uploadBytes": 74186752, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000087324, - "uploadBytes": 74842112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00033747, - "uploadBytes": 74186752, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00018741, - "uploadBytes": 75628544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000845532, - "uploadBytes": 74711040, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002024049, - "uploadBytes": 75628544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000137957, - "uploadBytes": 75497472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000918647, - "uploadBytes": 75628544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00099819, - "uploadBytes": 76414976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000346787, - "uploadBytes": 59703296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005152464, - "uploadBytes": 96075776, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000882265, - "uploadBytes": 73662464, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002819076, - "uploadBytes": 73924608, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002762377, - "uploadBytes": 73859072, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000263531, - "uploadBytes": 74383360, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002639027, - "uploadBytes": 74645504, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002950615, - "uploadBytes": 74907648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000801523, - "uploadBytes": 75104256, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000060967, - "uploadBytes": 75235328, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000074045, - "uploadBytes": 75366400, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00007309, - "uploadBytes": 75563008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000467553, - "uploadBytes": 75890688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000215499, - "uploadBytes": 76087296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000144367, - "uploadBytes": 76152832, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001304995, - "uploadBytes": 76546048, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00135447, - "uploadBytes": 76873728, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000899624, - "uploadBytes": 77070336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000153967, - "uploadBytes": 77201408, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000406801, - "uploadBytes": 59375616, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.009822981, - "uploadBytes": 78315520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000381027, - "uploadBytes": 78774272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001425849, - "uploadBytes": 78512128, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000157853, - "uploadBytes": 78970880, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004014651, - "uploadBytes": 79364096, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000894259, - "uploadBytes": 79364096, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001592951, - "uploadBytes": 80019456, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00025935, - "uploadBytes": 79626240, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072624, - "uploadBytes": 80281600, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000513436, - "uploadBytes": 80150528, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000234986, - "uploadBytes": 80674816, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000050577, - "uploadBytes": 80871424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001517285, - "uploadBytes": 81002496, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000242836, - "uploadBytes": 81461248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.0002124, - "uploadBytes": 81330176, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00097, - "uploadBytes": 81723392, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000101696, - "uploadBytes": 82116608, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001020011, - "uploadBytes": 82116608, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072368, - "uploadBytes": 52494336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00014106, - "uploadBytes": 103350272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000032158, - "uploadBytes": 101908480, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000335027, - "uploadBytes": 103612416, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00036854, - "uploadBytes": 102432768, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000652656, - "uploadBytes": 103153664, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000296979, - "uploadBytes": 103350272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000196313, - "uploadBytes": 103284736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000026131, - "uploadBytes": 104267776, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001409927, - "uploadBytes": 103809024, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000125728, - "uploadBytes": 104857600, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00020501, - "uploadBytes": 103219200, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000998701, - "uploadBytes": 105250816, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000365287, - "uploadBytes": 104202240, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000351789, - "uploadBytes": 105381888, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000951188, - "uploadBytes": 104792064, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000232966, - "uploadBytes": 105447424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00020409, - "uploadBytes": 105644032, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000780987, - "uploadBytes": 105644032, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000620997, - "uploadBytes": 63176704, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000635623, - "uploadBytes": 108003328, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000203706, - "uploadBytes": 75956224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000054346, - "uploadBytes": 76218368, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000134242, - "uploadBytes": 76414976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000160889, - "uploadBytes": 76611584, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000416, - "uploadBytes": 76939264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.0005163, - "uploadBytes": 77070336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000587926, - "uploadBytes": 77529088, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000632843, - "uploadBytes": 77398016, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001366011, - "uploadBytes": 77791232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00072928, - "uploadBytes": 78118912, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000521945, - "uploadBytes": 78249984, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000243261, - "uploadBytes": 78446592, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000338249, - "uploadBytes": 78381056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000549845, - "uploadBytes": 78774272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000520414, - "uploadBytes": 79036416, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00027941, - "uploadBytes": 79364096, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017072, - "uploadBytes": 79495168, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000267178, - "uploadBytes": 56885248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00023576, - "uploadBytes": 78905344, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000325544, - "uploadBytes": 74383360, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000329402, - "uploadBytes": 73400320, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000287899, - "uploadBytes": 74842112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000714275, - "uploadBytes": 73924608, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000127636, - "uploadBytes": 75235328, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000926457, - "uploadBytes": 74448896, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000526793, - "uploadBytes": 75890688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000499117, - "uploadBytes": 74907648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000204896, - "uploadBytes": 76152832, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000392255, - "uploadBytes": 75563008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000487299, - "uploadBytes": 76742656, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001170431, - "uploadBytes": 76087296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000389487, - "uploadBytes": 77135872, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000658832, - "uploadBytes": 76480512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000225518, - "uploadBytes": 77266944, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000576894, - "uploadBytes": 76873728, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000475991, - "uploadBytes": 77922304, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004248778, - "uploadBytes": 61931520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000857842, - "uploadBytes": 109510656, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000044593, - "uploadBytes": 109314048, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000613992, - "uploadBytes": 109117440, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011831, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00013635, - "uploadBytes": 109838336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000368396, - "uploadBytes": 110231552, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000165445, - "uploadBytes": 110428160, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000497313, - "uploadBytes": 110690304, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00066249, - "uploadBytes": 110690304, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000071566, - "uploadBytes": 110428160, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000575761, - "uploadBytes": 110821376, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001571401, - "uploadBytes": 110952448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000267802, - "uploadBytes": 111542272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000249034, - "uploadBytes": 111738880, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000471384, - "uploadBytes": 112001024, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000857318, - "uploadBytes": 112197632, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004955, - "uploadBytes": 112263168, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000099621, - "uploadBytes": 112852992, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017119, - "uploadBytes": 51773440, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000194767, - "uploadBytes": 108199936, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000374408, - "uploadBytes": 108658688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000589426, - "uploadBytes": 108855296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00045936, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00139308, - "uploadBytes": 109314048, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000348134, - "uploadBytes": 109641728, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000528601, - "uploadBytes": 109903872, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001652002, - "uploadBytes": 110034944, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000917701, - "uploadBytes": 110362624, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00127716, - "uploadBytes": 110428160, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001077158, - "uploadBytes": 110493696, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000424478, - "uploadBytes": 110297088, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000145946, - "uploadBytes": 110821376, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000434814, - "uploadBytes": 110821376, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000476688, - "uploadBytes": 111083520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000423063, - "uploadBytes": 111280128, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000033862, - "uploadBytes": 111673344, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000317131, - "uploadBytes": 112066560, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000599579, - "uploadBytes": 53608448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000055177, - "uploadBytes": 106692608, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019935, - "uploadBytes": 107085824, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000201621, - "uploadBytes": 107282432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001270224, - "uploadBytes": 108396544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000256294, - "uploadBytes": 108068864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000281634, - "uploadBytes": 107937792, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000136668, - "uploadBytes": 108265472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000248586, - "uploadBytes": 108724224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000410066, - "uploadBytes": 109117440, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00035711, - "uploadBytes": 108658688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000534402, - "uploadBytes": 108789760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000143202, - "uploadBytes": 109445120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000282205, - "uploadBytes": 109510656, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000261848, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000434885, - "uploadBytes": 109510656, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000880662, - "uploadBytes": 110559232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000080837, - "uploadBytes": 110362624, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000445249, - "uploadBytes": 110100480, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000222968, - "uploadBytes": 62586880, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000621157, - "uploadBytes": 75038720, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000067353, - "uploadBytes": 77529088, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000182375, - "uploadBytes": 77791232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001021615, - "uploadBytes": 76939264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00025063, - "uploadBytes": 77922304, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000560492, - "uploadBytes": 78249984, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000748758, - "uploadBytes": 78381056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001184215, - "uploadBytes": 78315520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000267448, - "uploadBytes": 78708736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000046348, - "uploadBytes": 79167488, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000633344, - "uploadBytes": 79298560, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000262903, - "uploadBytes": 79298560, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000744794, - "uploadBytes": 79495168, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000702511, - "uploadBytes": 79888384, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000379078, - "uploadBytes": 80216064, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000126884, - "uploadBytes": 79953920, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000639176, - "uploadBytes": 80281600, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000396881, - "uploadBytes": 80281600, - "downloadBytes": 0 - } - ], - "implementation": "go-libp2p", - "version": "v0.41", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.04843718, - "uploadBytes": 41943040, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.055286346, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.054831184, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053717899, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053040779, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.05398528, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.05241209, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053612699, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.05613233, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053141495, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053238149, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.055402889, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.054001118, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.057606844, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053758115, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.057512528, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.055581902, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.054252488, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.033159121, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005499, - "uploadBytes": 110886912, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000106583, - "uploadBytes": 109707264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013222, - "uploadBytes": 110166016, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000110248, - "uploadBytes": 109248512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000075956, - "uploadBytes": 108331008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008608, - "uploadBytes": 108789760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000095936, - "uploadBytes": 108593152, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00009842, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000106426, - "uploadBytes": 109772800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000044212, - "uploadBytes": 108134400, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027575, - "uploadBytes": 108986368, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000874094, - "uploadBytes": 106823680, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000064964, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000581399, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000024194, - "uploadBytes": 111476736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000150075, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000763, - "uploadBytes": 108986368, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000076949, - "uploadBytes": 109707264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000108615, - "uploadBytes": 44564480, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.058732655, - "uploadBytes": 114819072, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061668655, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062310688, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.060715311, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06159186, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062911033, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062042749, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063146565, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.0628490290000001, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067856546, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.063666228, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.062188428, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061856138, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.059670985, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061217159, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061094915, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.061608587, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.012416599, - "uploadBytes": 25165824, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.0573997529999999, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.046369181, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.043595928, - "uploadBytes": 83886080, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.150498081, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.142826652, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.141178191, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.141366434, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.198685563, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001236785, - "uploadBytes": 33554432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000069401, - "uploadBytes": 37158912, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000074389, - "uploadBytes": 35323904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.012650426, - "uploadBytes": 36569088, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.154387429, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.211845327, - "uploadBytes": 41943040, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.010678165, - "uploadBytes": 33554432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.007995867, - "uploadBytes": 33554432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.006401595, - "uploadBytes": 33554432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.030023191, - "uploadBytes": 25165824, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000071557, - "uploadBytes": 111738880, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008374, - "uploadBytes": 113246208, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000134672, - "uploadBytes": 107020288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000084412, - "uploadBytes": 111935488, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.065539062, - "uploadBytes": 109707264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001288473, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00013161, - "uploadBytes": 112721920, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00001555, - "uploadBytes": 109445120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00008515, - "uploadBytes": 111214592, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067241316, - "uploadBytes": 111214592, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002602214, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000086057, - "uploadBytes": 112656384, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000071973, - "uploadBytes": 111017984, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.067398852, - "uploadBytes": 111869952, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020401, - "uploadBytes": 111607808, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000122196, - "uploadBytes": 110755840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000048122, - "uploadBytes": 112787456, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.064829141, - "uploadBytes": 109445120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.036028805, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00219296, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004719981, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003759421, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002891281, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001881904, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.06744988, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00287273, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002391602, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002098324, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005140994, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005821478, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003992743, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003994066, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.004452591, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00453634, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001069734, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.0014981, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002299523, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000698823, - "uploadBytes": 25165824, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.048246269, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.047809007, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.042745213, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.047252285, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041532124, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.045798827, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.042419953, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.046888397, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.043066227, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.048785317, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.04281077, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.042517755, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041251932, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.046107138, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.047412151, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.044806632, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.042500584, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.065139825, - "uploadBytes": 33554432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041547359, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.039166461, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.043745405, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.03897941, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041301201, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.04198566, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041724347, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041017808, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.040642436, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.040371363, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.04168414, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041245833, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.041418666, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.037486977, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.039338603, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.03949051, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.037609156, - "uploadBytes": 117440512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.029562165, - "uploadBytes": 16777216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.007212235, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.006788882, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.072706776, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.010804252, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.034512828, - "uploadBytes": 100663296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.012144799, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.009469365, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.005645866, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000007121, - "uploadBytes": 61472768, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.053935059, - "uploadBytes": 64356352, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.052284725, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.050755952, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.047743682, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.048099507, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.04798912, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.047345969, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.045949286, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.046486692, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.056004356, - "uploadBytes": 33554432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.006397274, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003072399, - "uploadBytes": 109051904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.066717797, - "uploadBytes": 92274688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.029135513, - "uploadBytes": 92274688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.151276964, - "uploadBytes": 67108864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.174372862, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.174496199, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.170011986, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.165650211, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.160686931, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.161594152, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.160647912, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.161305673, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.162073284, - "uploadBytes": 50331648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.160581883, - "uploadBytes": 41943040, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.181654004, - "uploadBytes": 50331648, - "downloadBytes": 0 - } - ], - "implementation": "go-libp2p", - "version": "v0.42", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.01159089, - "uploadBytes": 49283072, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001331942, - "uploadBytes": 104923136, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000136598, - "uploadBytes": 103546880, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000753228, - "uploadBytes": 103481344, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000675677, - "uploadBytes": 104267776, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002477982, - "uploadBytes": 104988672, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00051638, - "uploadBytes": 104988672, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00010386, - "uploadBytes": 104595456, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00009964, - "uploadBytes": 104792064, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000398687, - "uploadBytes": 105971712, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000899646, - "uploadBytes": 105644032, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000573464, - "uploadBytes": 105381888, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000129148, - "uploadBytes": 105709568, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001112299, - "uploadBytes": 106430464, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000188943, - "uploadBytes": 105775104, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000469644, - "uploadBytes": 106430464, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000813904, - "uploadBytes": 106758144, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000726026, - "uploadBytes": 107282432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000272179, - "uploadBytes": 106758144, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000755892, - "uploadBytes": 60686336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000188021, - "uploadBytes": 72744960, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000271637, - "uploadBytes": 75038720, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000235458, - "uploadBytes": 75038720, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000315382, - "uploadBytes": 75104256, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00289434, - "uploadBytes": 76218368, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000596583, - "uploadBytes": 76218368, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000023809, - "uploadBytes": 75956224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000813957, - "uploadBytes": 75956224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003432, - "uploadBytes": 76939264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000386554, - "uploadBytes": 77070336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000317063, - "uploadBytes": 76677120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00065455, - "uploadBytes": 77201408, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000999478, - "uploadBytes": 77922304, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000449194, - "uploadBytes": 77791232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000573242, - "uploadBytes": 77791232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000763438, - "uploadBytes": 77987840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000565851, - "uploadBytes": 78512128, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072627, - "uploadBytes": 78643200, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000022253, - "uploadBytes": 62783488, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011984, - "uploadBytes": 79691776, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000353075, - "uploadBytes": 74842112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000203026, - "uploadBytes": 74973184, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000546829, - "uploadBytes": 75563008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000184584, - "uploadBytes": 76349440, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000989045, - "uploadBytes": 75563008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000641612, - "uploadBytes": 76087296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000035798, - "uploadBytes": 76152832, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00070731, - "uploadBytes": 76939264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000490721, - "uploadBytes": 77135872, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000564804, - "uploadBytes": 76873728, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000476644, - "uploadBytes": 77070336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000317425, - "uploadBytes": 77922304, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00021162, - "uploadBytes": 77791232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000681357, - "uploadBytes": 77791232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00045613, - "uploadBytes": 78184448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00081543, - "uploadBytes": 78184448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000791767, - "uploadBytes": 79101952, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000771, - "uploadBytes": 60162048, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000134612, - "uploadBytes": 95617024, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000873571, - "uploadBytes": 73531392, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000703882, - "uploadBytes": 73859072, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002007347, - "uploadBytes": 74121216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000900401, - "uploadBytes": 74317824, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001718791, - "uploadBytes": 74579968, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001391274, - "uploadBytes": 74842112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001389824, - "uploadBytes": 75038720, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00012526, - "uploadBytes": 75169792, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000374923, - "uploadBytes": 75366400, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000725395, - "uploadBytes": 75628544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000230813, - "uploadBytes": 76021760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000104468, - "uploadBytes": 76021760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001770505, - "uploadBytes": 76021760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00020317, - "uploadBytes": 76283904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000903723, - "uploadBytes": 76611584, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000443158, - "uploadBytes": 77004800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000249515, - "uploadBytes": 77135872, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000121835, - "uploadBytes": 61472768, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000120458, - "uploadBytes": 102105088, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000295132, - "uploadBytes": 105381888, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000149282, - "uploadBytes": 105185280, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000640685, - "uploadBytes": 105775104, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000244283, - "uploadBytes": 106037248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000181361, - "uploadBytes": 105906176, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001067956, - "uploadBytes": 106561536, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000756062, - "uploadBytes": 106758144, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000238597, - "uploadBytes": 106758144, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001476133, - "uploadBytes": 106889216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000620518, - "uploadBytes": 107216896, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000571818, - "uploadBytes": 107282432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000055004, - "uploadBytes": 107610112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00043886, - "uploadBytes": 107872256, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000209569, - "uploadBytes": 108068864, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000432212, - "uploadBytes": 108396544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000108211, - "uploadBytes": 108331008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000823021, - "uploadBytes": 108724224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.013018857, - "uploadBytes": 59768832, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000296295, - "uploadBytes": 76480512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000367538, - "uploadBytes": 76939264, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000305973, - "uploadBytes": 77004800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017932, - "uploadBytes": 77201408, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00040088, - "uploadBytes": 77266944, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00035677, - "uploadBytes": 77856768, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000666, - "uploadBytes": 77987840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000104, - "uploadBytes": 77987840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000920834, - "uploadBytes": 78184448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000836496, - "uploadBytes": 78708736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001289988, - "uploadBytes": 78774272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000345957, - "uploadBytes": 79495168, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000165908, - "uploadBytes": 79298560, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000313641, - "uploadBytes": 79429632, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000151377, - "uploadBytes": 79626240, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000805589, - "uploadBytes": 79888384, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011709, - "uploadBytes": 80281600, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001195522, - "uploadBytes": 80412672, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000356402, - "uploadBytes": 57868288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000055304, - "uploadBytes": 105381888, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000157532, - "uploadBytes": 105447424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000367861, - "uploadBytes": 105906176, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000465774, - "uploadBytes": 106037248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00030301, - "uploadBytes": 106364928, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000404347, - "uploadBytes": 106561536, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000799991, - "uploadBytes": 106954752, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000331774, - "uploadBytes": 107085824, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000326316, - "uploadBytes": 107413504, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001173425, - "uploadBytes": 107413504, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000523818, - "uploadBytes": 107413504, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000154611, - "uploadBytes": 107610112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000568285, - "uploadBytes": 107872256, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000091764, - "uploadBytes": 108134400, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000330891, - "uploadBytes": 108331008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000060074, - "uploadBytes": 108396544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000091853, - "uploadBytes": 108724224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001584703, - "uploadBytes": 108920832, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000249898, - "uploadBytes": 59703296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000722169, - "uploadBytes": 107741184, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001112546, - "uploadBytes": 108396544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009299, - "uploadBytes": 108658688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002036913, - "uploadBytes": 108920832, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000331968, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000344676, - "uploadBytes": 108789760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000093474, - "uploadBytes": 108789760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001665308, - "uploadBytes": 109445120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000348406, - "uploadBytes": 109772800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001737797, - "uploadBytes": 109641728, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000522571, - "uploadBytes": 109838336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00017988, - "uploadBytes": 110100480, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001571768, - "uploadBytes": 110100480, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000624936, - "uploadBytes": 110690304, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000293241, - "uploadBytes": 110952448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000361011, - "uploadBytes": 111083520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000239867, - "uploadBytes": 110821376, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000591801, - "uploadBytes": 111738880, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.006499507, - "uploadBytes": 52625408, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000781699, - "uploadBytes": 108527616, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00034744, - "uploadBytes": 108789760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000073624, - "uploadBytes": 108855296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000129849, - "uploadBytes": 109182976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00052746, - "uploadBytes": 109379584, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000704396, - "uploadBytes": 109576192, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001025174, - "uploadBytes": 109838336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000208582, - "uploadBytes": 110166016, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000196143, - "uploadBytes": 110493696, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000593779, - "uploadBytes": 110034944, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001028572, - "uploadBytes": 110493696, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000217983, - "uploadBytes": 110755840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000128677, - "uploadBytes": 110952448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00010834, - "uploadBytes": 111149056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000067081, - "uploadBytes": 111345664, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002077, - "uploadBytes": 111476736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000313697, - "uploadBytes": 111935488, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000439448, - "uploadBytes": 111869952, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000384887, - "uploadBytes": 55902208, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009546, - "uploadBytes": 104726528, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002731415, - "uploadBytes": 105709568, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000139971, - "uploadBytes": 106430464, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000966116, - "uploadBytes": 105381888, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000211629, - "uploadBytes": 107151360, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00051711, - "uploadBytes": 106037248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000129357, - "uploadBytes": 107413504, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000454979, - "uploadBytes": 106233856, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00018943, - "uploadBytes": 107479040, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000176057, - "uploadBytes": 107151360, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.00021102, - "uploadBytes": 107347968, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000137331, - "uploadBytes": 107610112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001432482, - "uploadBytes": 107347968, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000489145, - "uploadBytes": 108265472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000433048, - "uploadBytes": 107872256, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003137, - "uploadBytes": 108265472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000179534, - "uploadBytes": 108003328, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027768, - "uploadBytes": 109117440, - "downloadBytes": 0 - } - ], - "implementation": "go-libp2p", - "version": "v0.42", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 73990144, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 222822400, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 253034496, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259588096, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259784704, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260046848, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260112384, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 252444672, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 240582656, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 240910336, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250740736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 245039104, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248905728, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 239730688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 246153216, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 249888768, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 252706816, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 242614272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 244711424, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 71761920, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 232325120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259719168, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 263520256, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264503296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 262602752, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260702208, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264110080, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 262930432, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256507904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260505600, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 265158656, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264175616, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260308992, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 265617408, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264896512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 265093120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264372224, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264896512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 88670208, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 233111552, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002, - "uploadBytes": 253493248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258801664, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256901120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258539520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250937344, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 261160960, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259194880, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 244580352, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255787008, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256638976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 252575744, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256638976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 261619712, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254017536, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255262720, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256573440, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250871808, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 82051072, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 233963520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 253952000, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258932736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256835584, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258605056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259457024, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258670592, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257228800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255131648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254476288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258932736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257687552, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258342912, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258605056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259129344, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258670592, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259457024, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258998272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.003, - "uploadBytes": 81330176, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002, - "uploadBytes": 228720640, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 243007488, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 252248064, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248643584, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248512512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248774656, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 251265024, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 249167872, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 246480896, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250085376, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250413056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 253362176, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250806272, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248381440, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 247529472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250478592, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 249626624, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248840192, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 85917696, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 225837056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 252051456, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254476288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254476288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260440064, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256114688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258932736, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257753088, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 245039104, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 245104640, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 244776960, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248709120, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256704512, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254869504, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256638976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254476288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248250368, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248578048, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 77463552, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 233308160, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002, - "uploadBytes": 238092288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 251330560, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 246939648, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250019840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 249298944, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248119296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 248905728, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 242352128, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250871808, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 252182528, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 251723776, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254279680, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 253296640, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 251461632, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002, - "uploadBytes": 252051456, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 249626624, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 250019840, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 30605312, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.002, - "uploadBytes": 205914112, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258408448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260243456, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264830976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258801664, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 262078464, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 262668288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259850240, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 261029888, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264044544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 262668288, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 269418496, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264044544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264241152, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 259325952, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 260636672, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 264437760, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 261619712, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 50921472, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 229113856, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256507904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255459328, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257687552, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257359872, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257949696, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257884160, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 245301248, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 243793920, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258539520, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258080768, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257228800, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258605056, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257818624, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258408448, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 258342912, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257359872, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256638976, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 72220672, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 200671232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 241172480, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255393792, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256311296, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255852544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254869504, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 252313600, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254607360, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 247660544, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256507904, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255262720, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 249823232, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 254083072, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 257884160, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256049152, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 255983616, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 256114688, - "downloadBytes": 0 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 253820928, - "downloadBytes": 0 - } - ], - "implementation": "js-libp2p", - "version": "v2.8", - "transportStack": "tcp" - } - ], - "parameters": { - "uploadBytes": 9007199254740991, - "downloadBytes": 0 - } - }, - { - "name": "throughput/download", - "unit": "bit/s", - "results": [ - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.000208913, - "uploadBytes": 0, - "downloadBytes": 57262080 - }, - { - "type": "intermediary", - "timeSeconds": 1.005305337, - "uploadBytes": 0, - "downloadBytes": 73547776 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003669, - "uploadBytes": 0, - "downloadBytes": 73919552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072946, - "uploadBytes": 0, - "downloadBytes": 73290688 - }, - { - "type": "intermediary", - "timeSeconds": 1.000173736, - "uploadBytes": 0, - "downloadBytes": 73549192 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031623, - "uploadBytes": 0, - "downloadBytes": 73836216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000066857, - "uploadBytes": 0, - "downloadBytes": 74011584 - }, - { - "type": "intermediary", - "timeSeconds": 1.00047841, - "uploadBytes": 0, - "downloadBytes": 75022336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000046, - "uploadBytes": 0, - "downloadBytes": 74894096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000126082, - "uploadBytes": 0, - "downloadBytes": 75018696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000078288, - "uploadBytes": 0, - "downloadBytes": 75199728 - }, - { - "type": "intermediary", - "timeSeconds": 1.000047906, - "uploadBytes": 0, - "downloadBytes": 75501112 - }, - { - "type": "intermediary", - "timeSeconds": 1.000116191, - "uploadBytes": 0, - "downloadBytes": 76102872 - }, - { - "type": "intermediary", - "timeSeconds": 1.000248844, - "uploadBytes": 0, - "downloadBytes": 76633024 - }, - { - "type": "intermediary", - "timeSeconds": 1.000145972, - "uploadBytes": 0, - "downloadBytes": 76066664 - }, - { - "type": "intermediary", - "timeSeconds": 1.000368827, - "uploadBytes": 0, - "downloadBytes": 76578816 - }, - { - "type": "intermediary", - "timeSeconds": 1.000321979, - "uploadBytes": 0, - "downloadBytes": 76726272 - }, - { - "type": "intermediary", - "timeSeconds": 1.000134552, - "uploadBytes": 0, - "downloadBytes": 77233324 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027488, - "uploadBytes": 0, - "downloadBytes": 77631068 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017416, - "uploadBytes": 0, - "downloadBytes": 91101960 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018249, - "uploadBytes": 0, - "downloadBytes": 222209272 - }, - { - "type": "intermediary", - "timeSeconds": 1.000047648, - "uploadBytes": 0, - "downloadBytes": 224165888 - }, - { - "type": "intermediary", - "timeSeconds": 1.000109227, - "uploadBytes": 0, - "downloadBytes": 224198656 - }, - { - "type": "intermediary", - "timeSeconds": 1.000100006, - "uploadBytes": 0, - "downloadBytes": 223019008 - }, - { - "type": "intermediary", - "timeSeconds": 1.000179309, - "uploadBytes": 0, - "downloadBytes": 223166464 - }, - { - "type": "intermediary", - "timeSeconds": 1.000063623, - "uploadBytes": 0, - "downloadBytes": 223315332 - }, - { - "type": "intermediary", - "timeSeconds": 1.000016697, - "uploadBytes": 0, - "downloadBytes": 223085956 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017789, - "uploadBytes": 0, - "downloadBytes": 222754040 - }, - { - "type": "intermediary", - "timeSeconds": 1.000078038, - "uploadBytes": 0, - "downloadBytes": 223182848 - }, - { - "type": "intermediary", - "timeSeconds": 1.000024713, - "uploadBytes": 0, - "downloadBytes": 223256856 - }, - { - "type": "intermediary", - "timeSeconds": 1.000021947, - "uploadBytes": 0, - "downloadBytes": 222402049 - }, - { - "type": "intermediary", - "timeSeconds": 1.000087544, - "uploadBytes": 0, - "downloadBytes": 222864507 - }, - { - "type": "intermediary", - "timeSeconds": 1.000193508, - "uploadBytes": 0, - "downloadBytes": 223437932 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013818, - "uploadBytes": 0, - "downloadBytes": 223065896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000075673, - "uploadBytes": 0, - "downloadBytes": 222071000 - }, - { - "type": "intermediary", - "timeSeconds": 1.000110213, - "uploadBytes": 0, - "downloadBytes": 223600920 - }, - { - "type": "intermediary", - "timeSeconds": 1.000044441, - "uploadBytes": 0, - "downloadBytes": 223551208 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003406, - "uploadBytes": 0, - "downloadBytes": 222159128 - }, - { - "type": "intermediary", - "timeSeconds": 1.00030589, - "uploadBytes": 0, - "downloadBytes": 98717752 - }, - { - "type": "intermediary", - "timeSeconds": 1.000083572, - "uploadBytes": 0, - "downloadBytes": 232419272 - }, - { - "type": "intermediary", - "timeSeconds": 1.000025946, - "uploadBytes": 0, - "downloadBytes": 233144320 - }, - { - "type": "intermediary", - "timeSeconds": 1.000131508, - "uploadBytes": 0, - "downloadBytes": 231391232 - }, - { - "type": "intermediary", - "timeSeconds": 1.009634337, - "uploadBytes": 0, - "downloadBytes": 203274064 - }, - { - "type": "intermediary", - "timeSeconds": 1.000077748, - "uploadBytes": 0, - "downloadBytes": 87234876 - }, - { - "type": "intermediary", - "timeSeconds": 1.000064289, - "uploadBytes": 0, - "downloadBytes": 79700248 - }, - { - "type": "intermediary", - "timeSeconds": 1.000063046, - "uploadBytes": 0, - "downloadBytes": 80808712 - }, - { - "type": "intermediary", - "timeSeconds": 1.000211471, - "uploadBytes": 0, - "downloadBytes": 80380756 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020496, - "uploadBytes": 0, - "downloadBytes": 81144864 - }, - { - "type": "intermediary", - "timeSeconds": 1.000176396, - "uploadBytes": 0, - "downloadBytes": 81184132 - }, - { - "type": "intermediary", - "timeSeconds": 1.000052665, - "uploadBytes": 0, - "downloadBytes": 81481308 - }, - { - "type": "intermediary", - "timeSeconds": 1.000214558, - "uploadBytes": 0, - "downloadBytes": 81962652 - }, - { - "type": "intermediary", - "timeSeconds": 1.000260596, - "uploadBytes": 0, - "downloadBytes": 81988360 - }, - { - "type": "intermediary", - "timeSeconds": 1.000001538, - "uploadBytes": 0, - "downloadBytes": 82627336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013045, - "uploadBytes": 0, - "downloadBytes": 82297684 - }, - { - "type": "intermediary", - "timeSeconds": 1.000135596, - "uploadBytes": 0, - "downloadBytes": 83340320 - }, - { - "type": "intermediary", - "timeSeconds": 1.000167944, - "uploadBytes": 0, - "downloadBytes": 82908128 - }, - { - "type": "intermediary", - "timeSeconds": 1.000111051, - "uploadBytes": 0, - "downloadBytes": 83617436 - }, - { - "type": "intermediary", - "timeSeconds": 1.000253735, - "uploadBytes": 0, - "downloadBytes": 89358336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000015883, - "uploadBytes": 0, - "downloadBytes": 221178944 - }, - { - "type": "intermediary", - "timeSeconds": 1.000064234, - "uploadBytes": 0, - "downloadBytes": 221696960 - }, - { - "type": "intermediary", - "timeSeconds": 1.000050533, - "uploadBytes": 0, - "downloadBytes": 221331456 - }, - { - "type": "intermediary", - "timeSeconds": 1.000036876, - "uploadBytes": 0, - "downloadBytes": 223087376 - }, - { - "type": "intermediary", - "timeSeconds": 1.000012605, - "uploadBytes": 0, - "downloadBytes": 220304904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000174347, - "uploadBytes": 0, - "downloadBytes": 221917044 - }, - { - "type": "intermediary", - "timeSeconds": 1.042269372, - "uploadBytes": 0, - "downloadBytes": 209039220 - }, - { - "type": "intermediary", - "timeSeconds": 1.000221709, - "uploadBytes": 0, - "downloadBytes": 86820228 - }, - { - "type": "intermediary", - "timeSeconds": 1.000085564, - "uploadBytes": 0, - "downloadBytes": 76118652 - }, - { - "type": "intermediary", - "timeSeconds": 1.000471327, - "uploadBytes": 0, - "downloadBytes": 76972032 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008695, - "uploadBytes": 0, - "downloadBytes": 77204232 - }, - { - "type": "intermediary", - "timeSeconds": 1.000126088, - "uploadBytes": 0, - "downloadBytes": 76902820 - }, - { - "type": "intermediary", - "timeSeconds": 1.000100582, - "uploadBytes": 0, - "downloadBytes": 77254236 - }, - { - "type": "intermediary", - "timeSeconds": 1.000220964, - "uploadBytes": 0, - "downloadBytes": 78270604 - }, - { - "type": "intermediary", - "timeSeconds": 1.000088573, - "uploadBytes": 0, - "downloadBytes": 77744904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000388863, - "uploadBytes": 0, - "downloadBytes": 77800556 - }, - { - "type": "intermediary", - "timeSeconds": 1.000070081, - "uploadBytes": 0, - "downloadBytes": 78946584 - }, - { - "type": "intermediary", - "timeSeconds": 1.000071979, - "uploadBytes": 0, - "downloadBytes": 78681056 - }, - { - "type": "intermediary", - "timeSeconds": 1.000231594, - "uploadBytes": 0, - "downloadBytes": 89855392 - }, - { - "type": "intermediary", - "timeSeconds": 1.00004007, - "uploadBytes": 0, - "downloadBytes": 221669984 - }, - { - "type": "intermediary", - "timeSeconds": 1.000278237, - "uploadBytes": 0, - "downloadBytes": 224239920 - }, - { - "type": "intermediary", - "timeSeconds": 1.000083894, - "uploadBytes": 0, - "downloadBytes": 222411384 - }, - { - "type": "intermediary", - "timeSeconds": 1.000310377, - "uploadBytes": 0, - "downloadBytes": 222756849 - }, - { - "type": "intermediary", - "timeSeconds": 1.000096992, - "uploadBytes": 0, - "downloadBytes": 223004031 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000907, - "uploadBytes": 0, - "downloadBytes": 222493308 - }, - { - "type": "intermediary", - "timeSeconds": 1.000025139, - "uploadBytes": 0, - "downloadBytes": 156913804 - }, - { - "type": "intermediary", - "timeSeconds": 1.000257584, - "uploadBytes": 0, - "downloadBytes": 53579916 - }, - { - "type": "intermediary", - "timeSeconds": 1.000036122, - "uploadBytes": 0, - "downloadBytes": 53851369 - }, - { - "type": "intermediary", - "timeSeconds": 1.000189412, - "uploadBytes": 0, - "downloadBytes": 54122867 - }, - { - "type": "intermediary", - "timeSeconds": 1.002930186, - "uploadBytes": 0, - "downloadBytes": 55134984 - }, - { - "type": "intermediary", - "timeSeconds": 1.000257749, - "uploadBytes": 0, - "downloadBytes": 55134984 - }, - { - "type": "intermediary", - "timeSeconds": 1.000271624, - "uploadBytes": 0, - "downloadBytes": 54976232 - }, - { - "type": "intermediary", - "timeSeconds": 1.000195111, - "uploadBytes": 0, - "downloadBytes": 55565204 - }, - { - "type": "intermediary", - "timeSeconds": 1.000101428, - "uploadBytes": 0, - "downloadBytes": 55589500 - }, - { - "type": "intermediary", - "timeSeconds": 1.00030308, - "uploadBytes": 0, - "downloadBytes": 56251920 - }, - { - "type": "intermediary", - "timeSeconds": 1.000042933, - "uploadBytes": 0, - "downloadBytes": 56595424 - }, - { - "type": "intermediary", - "timeSeconds": 1.000245236, - "uploadBytes": 0, - "downloadBytes": 56589484 - }, - { - "type": "intermediary", - "timeSeconds": 1.000172268, - "uploadBytes": 0, - "downloadBytes": 58310656 - }, - { - "type": "intermediary", - "timeSeconds": 1.000015794, - "uploadBytes": 0, - "downloadBytes": 75005144 - }, - { - "type": "intermediary", - "timeSeconds": 1.000243494, - "uploadBytes": 0, - "downloadBytes": 75250296 - }, - { - "type": "intermediary", - "timeSeconds": 1.000001431, - "uploadBytes": 0, - "downloadBytes": 75303088 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031707, - "uploadBytes": 0, - "downloadBytes": 76137864 - }, - { - "type": "intermediary", - "timeSeconds": 1.000075805, - "uploadBytes": 0, - "downloadBytes": 76662137 - }, - { - "type": "intermediary", - "timeSeconds": 1.000025003, - "uploadBytes": 0, - "downloadBytes": 76367255 - }, - { - "type": "intermediary", - "timeSeconds": 1.000256068, - "uploadBytes": 0, - "downloadBytes": 76471208 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011923, - "uploadBytes": 0, - "downloadBytes": 76930768 - }, - { - "type": "intermediary", - "timeSeconds": 1.000054896, - "uploadBytes": 0, - "downloadBytes": 77445752 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031436, - "uploadBytes": 0, - "downloadBytes": 77933632 - }, - { - "type": "intermediary", - "timeSeconds": 1.000289106, - "uploadBytes": 0, - "downloadBytes": 77400848 - }, - { - "type": "intermediary", - "timeSeconds": 1.000080062, - "uploadBytes": 0, - "downloadBytes": 77905920 - }, - { - "type": "intermediary", - "timeSeconds": 1.000200624, - "uploadBytes": 0, - "downloadBytes": 77801952 - }, - { - "type": "intermediary", - "timeSeconds": 1.005324054, - "uploadBytes": 0, - "downloadBytes": 79124808 - }, - { - "type": "intermediary", - "timeSeconds": 1.000199705, - "uploadBytes": 0, - "downloadBytes": 79259292 - }, - { - "type": "intermediary", - "timeSeconds": 1.000501231, - "uploadBytes": 0, - "downloadBytes": 78641788 - }, - { - "type": "intermediary", - "timeSeconds": 1.000078781, - "uploadBytes": 0, - "downloadBytes": 79073420 - }, - { - "type": "intermediary", - "timeSeconds": 1.000098003, - "uploadBytes": 0, - "downloadBytes": 79260144 - }, - { - "type": "intermediary", - "timeSeconds": 1.000172013, - "uploadBytes": 0, - "downloadBytes": 90050616 - }, - { - "type": "intermediary", - "timeSeconds": 1.000159169, - "uploadBytes": 0, - "downloadBytes": 221622216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000128519, - "uploadBytes": 0, - "downloadBytes": 224293320 - }, - { - "type": "intermediary", - "timeSeconds": 1.000244904, - "uploadBytes": 0, - "downloadBytes": 120161657 - }, - { - "type": "intermediary", - "timeSeconds": 1.000112077, - "uploadBytes": 0, - "downloadBytes": 76742671 - }, - { - "type": "intermediary", - "timeSeconds": 1.000134987, - "uploadBytes": 0, - "downloadBytes": 77081056 - }, - { - "type": "intermediary", - "timeSeconds": 1.000043858, - "uploadBytes": 0, - "downloadBytes": 77500568 - }, - { - "type": "intermediary", - "timeSeconds": 1.00020848, - "uploadBytes": 0, - "downloadBytes": 78344040 - }, - { - "type": "intermediary", - "timeSeconds": 1.000062447, - "uploadBytes": 0, - "downloadBytes": 77923720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000140429, - "uploadBytes": 0, - "downloadBytes": 78013520 - }, - { - "type": "intermediary", - "timeSeconds": 1.000259407, - "uploadBytes": 0, - "downloadBytes": 78050552 - }, - { - "type": "intermediary", - "timeSeconds": 1.00006105, - "uploadBytes": 0, - "downloadBytes": 78708736 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008568, - "uploadBytes": 0, - "downloadBytes": 79118336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000029961, - "uploadBytes": 0, - "downloadBytes": 78651672 - }, - { - "type": "intermediary", - "timeSeconds": 1.000030409, - "uploadBytes": 0, - "downloadBytes": 79194608 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017672, - "uploadBytes": 0, - "downloadBytes": 79487256 - }, - { - "type": "intermediary", - "timeSeconds": 1.000083176, - "uploadBytes": 0, - "downloadBytes": 79960420 - }, - { - "type": "intermediary", - "timeSeconds": 1.000075283, - "uploadBytes": 0, - "downloadBytes": 79493756 - }, - { - "type": "intermediary", - "timeSeconds": 1.000210606, - "uploadBytes": 0, - "downloadBytes": 79822848 - }, - { - "type": "intermediary", - "timeSeconds": 1.000054704, - "uploadBytes": 0, - "downloadBytes": 85900152 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020253, - "uploadBytes": 0, - "downloadBytes": 219071624 - }, - { - "type": "intermediary", - "timeSeconds": 1.000074523, - "uploadBytes": 0, - "downloadBytes": 218852401 - }, - { - "type": "intermediary", - "timeSeconds": 1.000094299, - "uploadBytes": 0, - "downloadBytes": 219698127 - }, - { - "type": "intermediary", - "timeSeconds": 1.000100158, - "uploadBytes": 0, - "downloadBytes": 219266264 - }, - { - "type": "intermediary", - "timeSeconds": 1.000200854, - "uploadBytes": 0, - "downloadBytes": 218710824 - }, - { - "type": "intermediary", - "timeSeconds": 1.000086908, - "uploadBytes": 0, - "downloadBytes": 218637980 - }, - { - "type": "intermediary", - "timeSeconds": 1.000001117, - "uploadBytes": 0, - "downloadBytes": 218856060 - }, - { - "type": "intermediary", - "timeSeconds": 1.000131302, - "uploadBytes": 0, - "downloadBytes": 218640244 - }, - { - "type": "intermediary", - "timeSeconds": 1.000053964, - "uploadBytes": 0, - "downloadBytes": 219119616 - }, - { - "type": "intermediary", - "timeSeconds": 1.000068666, - "uploadBytes": 0, - "downloadBytes": 218307476 - }, - { - "type": "intermediary", - "timeSeconds": 1.000023615, - "uploadBytes": 0, - "downloadBytes": 218974984 - }, - { - "type": "intermediary", - "timeSeconds": 1.00006882, - "uploadBytes": 0, - "downloadBytes": 218480640 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008847, - "uploadBytes": 0, - "downloadBytes": 219060580 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005268, - "uploadBytes": 0, - "downloadBytes": 218886004 - }, - { - "type": "intermediary", - "timeSeconds": 1.000026198, - "uploadBytes": 0, - "downloadBytes": 218677248 - }, - { - "type": "intermediary", - "timeSeconds": 1.000244354, - "uploadBytes": 0, - "downloadBytes": 218621596 - }, - { - "type": "intermediary", - "timeSeconds": 1.000349818, - "uploadBytes": 0, - "downloadBytes": 218372452 - }, - { - "type": "intermediary", - "timeSeconds": 1.000317368, - "uploadBytes": 0, - "downloadBytes": 219435148 - }, - { - "type": "intermediary", - "timeSeconds": 1.000049399, - "uploadBytes": 0, - "downloadBytes": 89415792 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000566, - "uploadBytes": 0, - "downloadBytes": 221352280 - }, - { - "type": "intermediary", - "timeSeconds": 1.028973184, - "uploadBytes": 0, - "downloadBytes": 210213192 - }, - { - "type": "intermediary", - "timeSeconds": 1.000067091, - "uploadBytes": 0, - "downloadBytes": 94483696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000119752, - "uploadBytes": 0, - "downloadBytes": 76547464 - }, - { - "type": "intermediary", - "timeSeconds": 1.000117709, - "uploadBytes": 0, - "downloadBytes": 77828248 - }, - { - "type": "intermediary", - "timeSeconds": 1.000032157, - "uploadBytes": 0, - "downloadBytes": 77015520 - }, - { - "type": "intermediary", - "timeSeconds": 1.000226709, - "uploadBytes": 0, - "downloadBytes": 77381632 - }, - { - "type": "intermediary", - "timeSeconds": 1.000106576, - "uploadBytes": 0, - "downloadBytes": 77771208 - }, - { - "type": "intermediary", - "timeSeconds": 1.000184745, - "uploadBytes": 0, - "downloadBytes": 78510680 - }, - { - "type": "intermediary", - "timeSeconds": 1.000233329, - "uploadBytes": 0, - "downloadBytes": 78096880 - }, - { - "type": "intermediary", - "timeSeconds": 1.000142008, - "uploadBytes": 0, - "downloadBytes": 78240660 - }, - { - "type": "intermediary", - "timeSeconds": 1.000110982, - "uploadBytes": 0, - "downloadBytes": 78625389 - }, - { - "type": "intermediary", - "timeSeconds": 1.000115473, - "uploadBytes": 0, - "downloadBytes": 79051403 - }, - { - "type": "intermediary", - "timeSeconds": 1.000131762, - "uploadBytes": 0, - "downloadBytes": 78977380 - }, - { - "type": "intermediary", - "timeSeconds": 1.000093605, - "uploadBytes": 0, - "downloadBytes": 78766360 - }, - { - "type": "intermediary", - "timeSeconds": 1.000157335, - "uploadBytes": 0, - "downloadBytes": 79912680 - }, - { - "type": "intermediary", - "timeSeconds": 1.000061284, - "uploadBytes": 0, - "downloadBytes": 79822848 - }, - { - "type": "intermediary", - "timeSeconds": 1.000282547, - "uploadBytes": 0, - "downloadBytes": 79593472 - }, - { - "type": "intermediary", - "timeSeconds": 1.000033154, - "uploadBytes": 0, - "downloadBytes": 91618168 - }, - { - "type": "intermediary", - "timeSeconds": 1.000074794, - "uploadBytes": 0, - "downloadBytes": 223118472 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017754, - "uploadBytes": 0, - "downloadBytes": 224002048 - }, - { - "type": "intermediary", - "timeSeconds": 1.000136749, - "uploadBytes": 0, - "downloadBytes": 150326032 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002769, - "uploadBytes": 0, - "downloadBytes": 77412984 - }, - { - "type": "intermediary", - "timeSeconds": 1.000016617, - "uploadBytes": 0, - "downloadBytes": 77716392 - }, - { - "type": "intermediary", - "timeSeconds": 1.000037106, - "uploadBytes": 0, - "downloadBytes": 77744912 - }, - { - "type": "intermediary", - "timeSeconds": 1.000133265, - "uploadBytes": 0, - "downloadBytes": 78025664 - }, - { - "type": "intermediary", - "timeSeconds": 1.000224299, - "uploadBytes": 0, - "downloadBytes": 78228512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000119607, - "uploadBytes": 0, - "downloadBytes": 78522864 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018048, - "uploadBytes": 0, - "downloadBytes": 78925964 - }, - { - "type": "intermediary", - "timeSeconds": 1.000104344, - "uploadBytes": 0, - "downloadBytes": 79355624 - }, - { - "type": "intermediary", - "timeSeconds": 1.000099951, - "uploadBytes": 0, - "downloadBytes": 79411836 - }, - { - "type": "intermediary", - "timeSeconds": 1.000079919, - "uploadBytes": 0, - "downloadBytes": 79527936 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027463, - "uploadBytes": 0, - "downloadBytes": 79834144 - }, - { - "type": "intermediary", - "timeSeconds": 1.000234077, - "uploadBytes": 0, - "downloadBytes": 79930476 - }, - { - "type": "intermediary", - "timeSeconds": 1.000034196, - "uploadBytes": 0, - "downloadBytes": 80411260 - }, - { - "type": "intermediary", - "timeSeconds": 1.000207695, - "uploadBytes": 0, - "downloadBytes": 80622840 - }, - { - "type": "intermediary", - "timeSeconds": 1.000183328, - "uploadBytes": 0, - "downloadBytes": 80908428 - } - ], - "implementation": "quic-go", - "version": "v0.45", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "intermediate", - "timeSeconds": 1.000080905, - "uploadBytes": 0, - "downloadBytes": 38256640 - }, - { - "type": "intermediate", - "timeSeconds": 1.000084748, - "uploadBytes": 0, - "downloadBytes": 162959360 - }, - { - "type": "intermediate", - "timeSeconds": 1.000152426, - "uploadBytes": 0, - "downloadBytes": 164077568 - }, - { - "type": "intermediate", - "timeSeconds": 1.000192402, - "uploadBytes": 0, - "downloadBytes": 161673216 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082972, - "uploadBytes": 0, - "downloadBytes": 163944448 - }, - { - "type": "intermediate", - "timeSeconds": 1.000113987, - "uploadBytes": 0, - "downloadBytes": 164334592 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080751, - "uploadBytes": 0, - "downloadBytes": 166190080 - }, - { - "type": "intermediate", - "timeSeconds": 1.000057814, - "uploadBytes": 0, - "downloadBytes": 164969472 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079718, - "uploadBytes": 0, - "downloadBytes": 165869568 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007122, - "uploadBytes": 0, - "downloadBytes": 163847168 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077185, - "uploadBytes": 0, - "downloadBytes": 167099392 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077404, - "uploadBytes": 0, - "downloadBytes": 162391040 - }, - { - "type": "intermediate", - "timeSeconds": 1.000119347, - "uploadBytes": 0, - "downloadBytes": 163547136 - }, - { - "type": "intermediate", - "timeSeconds": 1.00012993, - "uploadBytes": 0, - "downloadBytes": 171642880 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076068, - "uploadBytes": 0, - "downloadBytes": 171638784 - }, - { - "type": "intermediate", - "timeSeconds": 1.00006718, - "uploadBytes": 0, - "downloadBytes": 171290624 - }, - { - "type": "intermediate", - "timeSeconds": 1.000121562, - "uploadBytes": 0, - "downloadBytes": 170110976 - }, - { - "type": "intermediate", - "timeSeconds": 1.000204974, - "uploadBytes": 0, - "downloadBytes": 168030208 - }, - { - "type": "intermediate", - "timeSeconds": 1.000066252, - "uploadBytes": 0, - "downloadBytes": 170284032 - }, - { - "type": "intermediate", - "timeSeconds": 1.000092426, - "uploadBytes": 0, - "downloadBytes": 25296896 - }, - { - "type": "intermediate", - "timeSeconds": 1.000090288, - "uploadBytes": 0, - "downloadBytes": 172213248 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059673, - "uploadBytes": 0, - "downloadBytes": 164371456 - }, - { - "type": "intermediate", - "timeSeconds": 1.000099854, - "uploadBytes": 0, - "downloadBytes": 168256512 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076457, - "uploadBytes": 0, - "downloadBytes": 173122560 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079846, - "uploadBytes": 0, - "downloadBytes": 173535232 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082007, - "uploadBytes": 0, - "downloadBytes": 174454784 - }, - { - "type": "intermediate", - "timeSeconds": 1.000207401, - "uploadBytes": 0, - "downloadBytes": 169675776 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079053, - "uploadBytes": 0, - "downloadBytes": 164945920 - }, - { - "type": "intermediate", - "timeSeconds": 1.00006532, - "uploadBytes": 0, - "downloadBytes": 166285312 - }, - { - "type": "intermediate", - "timeSeconds": 0.999985819, - "uploadBytes": 0, - "downloadBytes": 168545280 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086417, - "uploadBytes": 0, - "downloadBytes": 168822784 - }, - { - "type": "intermediate", - "timeSeconds": 0.999994959, - "uploadBytes": 0, - "downloadBytes": 170662912 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074954, - "uploadBytes": 0, - "downloadBytes": 164487168 - }, - { - "type": "intermediate", - "timeSeconds": 1.000123425, - "uploadBytes": 0, - "downloadBytes": 164977664 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077448, - "uploadBytes": 0, - "downloadBytes": 164507648 - }, - { - "type": "intermediate", - "timeSeconds": 1.000090109, - "uploadBytes": 0, - "downloadBytes": 172344320 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074928, - "uploadBytes": 0, - "downloadBytes": 172907520 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079642, - "uploadBytes": 0, - "downloadBytes": 169247744 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083837, - "uploadBytes": 0, - "downloadBytes": 46701568 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007824, - "uploadBytes": 0, - "downloadBytes": 180072448 - }, - { - "type": "intermediate", - "timeSeconds": 1.000022123, - "uploadBytes": 0, - "downloadBytes": 180143104 - }, - { - "type": "intermediate", - "timeSeconds": 1.000099133, - "uploadBytes": 0, - "downloadBytes": 183926784 - }, - { - "type": "intermediate", - "timeSeconds": 1.000165674, - "uploadBytes": 0, - "downloadBytes": 183361536 - }, - { - "type": "intermediate", - "timeSeconds": 1.000052671, - "uploadBytes": 0, - "downloadBytes": 184804352 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075758, - "uploadBytes": 0, - "downloadBytes": 185899008 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081166, - "uploadBytes": 0, - "downloadBytes": 184764416 - }, - { - "type": "intermediate", - "timeSeconds": 1.000095831, - "uploadBytes": 0, - "downloadBytes": 184025088 - }, - { - "type": "intermediate", - "timeSeconds": 1.000091705, - "uploadBytes": 0, - "downloadBytes": 175729664 - }, - { - "type": "intermediate", - "timeSeconds": 1.000066179, - "uploadBytes": 0, - "downloadBytes": 175228928 - }, - { - "type": "intermediate", - "timeSeconds": 1.000090718, - "uploadBytes": 0, - "downloadBytes": 180385792 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072194, - "uploadBytes": 0, - "downloadBytes": 180108288 - }, - { - "type": "intermediate", - "timeSeconds": 1.000097711, - "uploadBytes": 0, - "downloadBytes": 181310464 - }, - { - "type": "intermediate", - "timeSeconds": 1.000068646, - "uploadBytes": 0, - "downloadBytes": 185290752 - }, - { - "type": "intermediate", - "timeSeconds": 1.00018569, - "uploadBytes": 0, - "downloadBytes": 186020864 - }, - { - "type": "intermediate", - "timeSeconds": 1.000117419, - "uploadBytes": 0, - "downloadBytes": 186165248 - }, - { - "type": "intermediate", - "timeSeconds": 1.000097273, - "uploadBytes": 0, - "downloadBytes": 182898688 - }, - { - "type": "intermediate", - "timeSeconds": 1.000061462, - "uploadBytes": 0, - "downloadBytes": 185893888 - }, - { - "type": "intermediate", - "timeSeconds": 1.000069144, - "uploadBytes": 0, - "downloadBytes": 44788736 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083451, - "uploadBytes": 0, - "downloadBytes": 165929984 - }, - { - "type": "intermediate", - "timeSeconds": 1.000065594, - "uploadBytes": 0, - "downloadBytes": 166210560 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079276, - "uploadBytes": 0, - "downloadBytes": 166544384 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081682, - "uploadBytes": 0, - "downloadBytes": 170698752 - }, - { - "type": "intermediate", - "timeSeconds": 1.000183886, - "uploadBytes": 0, - "downloadBytes": 173173760 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072231, - "uploadBytes": 0, - "downloadBytes": 174295040 - }, - { - "type": "intermediate", - "timeSeconds": 1.000133031, - "uploadBytes": 0, - "downloadBytes": 169540608 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073776, - "uploadBytes": 0, - "downloadBytes": 166224896 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078458, - "uploadBytes": 0, - "downloadBytes": 165783552 - }, - { - "type": "intermediate", - "timeSeconds": 1.000106593, - "uploadBytes": 0, - "downloadBytes": 169678848 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080749, - "uploadBytes": 0, - "downloadBytes": 164453376 - }, - { - "type": "intermediate", - "timeSeconds": 1.000096886, - "uploadBytes": 0, - "downloadBytes": 164907008 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059623, - "uploadBytes": 0, - "downloadBytes": 161627136 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079199, - "uploadBytes": 0, - "downloadBytes": 160330752 - }, - { - "type": "intermediate", - "timeSeconds": 1.000101288, - "uploadBytes": 0, - "downloadBytes": 160116736 - }, - { - "type": "intermediate", - "timeSeconds": 1.000067136, - "uploadBytes": 0, - "downloadBytes": 163528704 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086031, - "uploadBytes": 0, - "downloadBytes": 164186112 - }, - { - "type": "intermediate", - "timeSeconds": 1.00016152, - "uploadBytes": 0, - "downloadBytes": 161710080 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083278, - "uploadBytes": 0, - "downloadBytes": 45351936 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073406, - "uploadBytes": 0, - "downloadBytes": 179475456 - }, - { - "type": "intermediate", - "timeSeconds": 1.000125185, - "uploadBytes": 0, - "downloadBytes": 178515968 - }, - { - "type": "intermediate", - "timeSeconds": 1.000170689, - "uploadBytes": 0, - "downloadBytes": 181334016 - }, - { - "type": "intermediate", - "timeSeconds": 1.0000679, - "uploadBytes": 0, - "downloadBytes": 181630976 - }, - { - "type": "intermediate", - "timeSeconds": 1.00016349, - "uploadBytes": 0, - "downloadBytes": 181456896 - }, - { - "type": "intermediate", - "timeSeconds": 1.00008124, - "uploadBytes": 0, - "downloadBytes": 180460544 - }, - { - "type": "intermediate", - "timeSeconds": 1.000085512, - "uploadBytes": 0, - "downloadBytes": 179263488 - }, - { - "type": "intermediate", - "timeSeconds": 1.000169, - "uploadBytes": 0, - "downloadBytes": 179375104 - }, - { - "type": "intermediate", - "timeSeconds": 1.00009086, - "uploadBytes": 0, - "downloadBytes": 179604480 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059649, - "uploadBytes": 0, - "downloadBytes": 178608128 - }, - { - "type": "intermediate", - "timeSeconds": 1.000113152, - "uploadBytes": 0, - "downloadBytes": 180533248 - }, - { - "type": "intermediate", - "timeSeconds": 0.9999729, - "uploadBytes": 0, - "downloadBytes": 182085632 - }, - { - "type": "intermediate", - "timeSeconds": 1.000090794, - "uploadBytes": 0, - "downloadBytes": 174835712 - }, - { - "type": "intermediate", - "timeSeconds": 1.00010758, - "uploadBytes": 0, - "downloadBytes": 171332608 - }, - { - "type": "intermediate", - "timeSeconds": 1.00012191, - "uploadBytes": 0, - "downloadBytes": 176576512 - }, - { - "type": "intermediate", - "timeSeconds": 1.000093044, - "uploadBytes": 0, - "downloadBytes": 179656704 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080039, - "uploadBytes": 0, - "downloadBytes": 181163008 - }, - { - "type": "intermediate", - "timeSeconds": 1.000069966, - "uploadBytes": 0, - "downloadBytes": 178973696 - }, - { - "type": "intermediate", - "timeSeconds": 1.000097756, - "uploadBytes": 0, - "downloadBytes": 48024576 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079915, - "uploadBytes": 0, - "downloadBytes": 186293248 - }, - { - "type": "intermediate", - "timeSeconds": 1.000122577, - "uploadBytes": 0, - "downloadBytes": 182059008 - }, - { - "type": "intermediate", - "timeSeconds": 1.000179828, - "uploadBytes": 0, - "downloadBytes": 183398400 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081083, - "uploadBytes": 0, - "downloadBytes": 182749184 - }, - { - "type": "intermediate", - "timeSeconds": 1.00016245, - "uploadBytes": 0, - "downloadBytes": 185364480 - }, - { - "type": "intermediate", - "timeSeconds": 1.000135189, - "uploadBytes": 0, - "downloadBytes": 187836416 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072055, - "uploadBytes": 0, - "downloadBytes": 188669952 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076113, - "uploadBytes": 0, - "downloadBytes": 184324096 - }, - { - "type": "intermediate", - "timeSeconds": 1.000111124, - "uploadBytes": 0, - "downloadBytes": 189568000 - }, - { - "type": "intermediate", - "timeSeconds": 1.000065651, - "uploadBytes": 0, - "downloadBytes": 189980672 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077843, - "uploadBytes": 0, - "downloadBytes": 190258176 - }, - { - "type": "intermediate", - "timeSeconds": 1.000063233, - "uploadBytes": 0, - "downloadBytes": 183616512 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007819, - "uploadBytes": 0, - "downloadBytes": 188234752 - }, - { - "type": "intermediate", - "timeSeconds": 1.000135237, - "uploadBytes": 0, - "downloadBytes": 185070592 - }, - { - "type": "intermediate", - "timeSeconds": 1.000168037, - "uploadBytes": 0, - "downloadBytes": 179618816 - }, - { - "type": "intermediate", - "timeSeconds": 1.000149615, - "uploadBytes": 0, - "downloadBytes": 187368448 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078816, - "uploadBytes": 0, - "downloadBytes": 183443456 - }, - { - "type": "intermediate", - "timeSeconds": 1.000169578, - "uploadBytes": 0, - "downloadBytes": 181675008 - }, - { - "type": "intermediate", - "timeSeconds": 1.000085271, - "uploadBytes": 0, - "downloadBytes": 55548928 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070118, - "uploadBytes": 0, - "downloadBytes": 168722432 - }, - { - "type": "intermediate", - "timeSeconds": 1.000194071, - "uploadBytes": 0, - "downloadBytes": 163650560 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083063, - "uploadBytes": 0, - "downloadBytes": 164211712 - }, - { - "type": "intermediate", - "timeSeconds": 1.000091971, - "uploadBytes": 0, - "downloadBytes": 166194176 - }, - { - "type": "intermediate", - "timeSeconds": 1.000088856, - "uploadBytes": 0, - "downloadBytes": 174236672 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074798, - "uploadBytes": 0, - "downloadBytes": 170925056 - }, - { - "type": "intermediate", - "timeSeconds": 1.000161337, - "uploadBytes": 0, - "downloadBytes": 174099456 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075776, - "uploadBytes": 0, - "downloadBytes": 165898240 - }, - { - "type": "intermediate", - "timeSeconds": 1.000160658, - "uploadBytes": 0, - "downloadBytes": 178787328 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079047, - "uploadBytes": 0, - "downloadBytes": 169417728 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086767, - "uploadBytes": 0, - "downloadBytes": 172401664 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007815, - "uploadBytes": 0, - "downloadBytes": 173669376 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081794, - "uploadBytes": 0, - "downloadBytes": 175241216 - }, - { - "type": "intermediate", - "timeSeconds": 1.000063512, - "uploadBytes": 0, - "downloadBytes": 167067648 - }, - { - "type": "intermediate", - "timeSeconds": 1.000087119, - "uploadBytes": 0, - "downloadBytes": 172520448 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082459, - "uploadBytes": 0, - "downloadBytes": 173070336 - }, - { - "type": "intermediate", - "timeSeconds": 1.000137743, - "uploadBytes": 0, - "downloadBytes": 176729088 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072658, - "uploadBytes": 0, - "downloadBytes": 178243584 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086262, - "uploadBytes": 0, - "downloadBytes": 59020288 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078035, - "uploadBytes": 0, - "downloadBytes": 181695488 - }, - { - "type": "intermediate", - "timeSeconds": 1.000161439, - "uploadBytes": 0, - "downloadBytes": 187697152 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078331, - "uploadBytes": 0, - "downloadBytes": 178757632 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074959, - "uploadBytes": 0, - "downloadBytes": 180088832 - }, - { - "type": "intermediate", - "timeSeconds": 1.000117873, - "uploadBytes": 0, - "downloadBytes": 178302976 - }, - { - "type": "intermediate", - "timeSeconds": 1.000153471, - "uploadBytes": 0, - "downloadBytes": 186750976 - }, - { - "type": "intermediate", - "timeSeconds": 1.000148803, - "uploadBytes": 0, - "downloadBytes": 181984256 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083765, - "uploadBytes": 0, - "downloadBytes": 180516864 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077929, - "uploadBytes": 0, - "downloadBytes": 180895744 - }, - { - "type": "intermediate", - "timeSeconds": 1.000089354, - "uploadBytes": 0, - "downloadBytes": 178840576 - }, - { - "type": "intermediate", - "timeSeconds": 1.000173085, - "uploadBytes": 0, - "downloadBytes": 181232640 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078651, - "uploadBytes": 0, - "downloadBytes": 181315584 - }, - { - "type": "intermediate", - "timeSeconds": 1.000105363, - "uploadBytes": 0, - "downloadBytes": 188195840 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077194, - "uploadBytes": 0, - "downloadBytes": 184397824 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072481, - "uploadBytes": 0, - "downloadBytes": 178348032 - }, - { - "type": "intermediate", - "timeSeconds": 1.000126801, - "uploadBytes": 0, - "downloadBytes": 177085440 - }, - { - "type": "intermediate", - "timeSeconds": 1.000084698, - "uploadBytes": 0, - "downloadBytes": 186012672 - }, - { - "type": "intermediate", - "timeSeconds": 1.000168033, - "uploadBytes": 0, - "downloadBytes": 184412160 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080597, - "uploadBytes": 0, - "downloadBytes": 63340544 - }, - { - "type": "intermediate", - "timeSeconds": 1.000100882, - "uploadBytes": 0, - "downloadBytes": 165841920 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078664, - "uploadBytes": 0, - "downloadBytes": 160969728 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059605, - "uploadBytes": 0, - "downloadBytes": 169259008 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078822, - "uploadBytes": 0, - "downloadBytes": 169585664 - }, - { - "type": "intermediate", - "timeSeconds": 1.00006635, - "uploadBytes": 0, - "downloadBytes": 170628096 - }, - { - "type": "intermediate", - "timeSeconds": 1.00008153, - "uploadBytes": 0, - "downloadBytes": 166647808 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079786, - "uploadBytes": 0, - "downloadBytes": 160706560 - }, - { - "type": "intermediate", - "timeSeconds": 1.000040195, - "uploadBytes": 0, - "downloadBytes": 165746688 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072913, - "uploadBytes": 0, - "downloadBytes": 167583744 - }, - { - "type": "intermediate", - "timeSeconds": 1.000004741, - "uploadBytes": 0, - "downloadBytes": 173679616 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070708, - "uploadBytes": 0, - "downloadBytes": 166601728 - }, - { - "type": "intermediate", - "timeSeconds": 1.000191064, - "uploadBytes": 0, - "downloadBytes": 166770688 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086365, - "uploadBytes": 0, - "downloadBytes": 170425344 - }, - { - "type": "intermediate", - "timeSeconds": 1.000092657, - "uploadBytes": 0, - "downloadBytes": 168137728 - }, - { - "type": "intermediate", - "timeSeconds": 1.000089823, - "uploadBytes": 0, - "downloadBytes": 163970048 - }, - { - "type": "intermediate", - "timeSeconds": 1.000058164, - "uploadBytes": 0, - "downloadBytes": 163352576 - }, - { - "type": "intermediate", - "timeSeconds": 1.00011815, - "uploadBytes": 0, - "downloadBytes": 169501696 - }, - { - "type": "intermediate", - "timeSeconds": 1.000053356, - "uploadBytes": 0, - "downloadBytes": 168523776 - }, - { - "type": "intermediate", - "timeSeconds": 1.000085713, - "uploadBytes": 0, - "downloadBytes": 46937088 - }, - { - "type": "intermediate", - "timeSeconds": 1.000067482, - "uploadBytes": 0, - "downloadBytes": 171830272 - }, - { - "type": "intermediate", - "timeSeconds": 1.000133645, - "uploadBytes": 0, - "downloadBytes": 173402112 - }, - { - "type": "intermediate", - "timeSeconds": 1.000061444, - "uploadBytes": 0, - "downloadBytes": 173431808 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080483, - "uploadBytes": 0, - "downloadBytes": 168727552 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078625, - "uploadBytes": 0, - "downloadBytes": 164285440 - }, - { - "type": "intermediate", - "timeSeconds": 1.000057709, - "uploadBytes": 0, - "downloadBytes": 163108864 - }, - { - "type": "intermediate", - "timeSeconds": 1.000138957, - "uploadBytes": 0, - "downloadBytes": 166816768 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081853, - "uploadBytes": 0, - "downloadBytes": 173115392 - }, - { - "type": "intermediate", - "timeSeconds": 1.000134396, - "uploadBytes": 0, - "downloadBytes": 173210624 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078903, - "uploadBytes": 0, - "downloadBytes": 174022656 - }, - { - "type": "intermediate", - "timeSeconds": 1.000099733, - "uploadBytes": 0, - "downloadBytes": 171855872 - }, - { - "type": "intermediate", - "timeSeconds": 0.999984127, - "uploadBytes": 0, - "downloadBytes": 170978304 - }, - { - "type": "intermediate", - "timeSeconds": 1.000053491, - "uploadBytes": 0, - "downloadBytes": 171808768 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077459, - "uploadBytes": 0, - "downloadBytes": 166726656 - }, - { - "type": "intermediate", - "timeSeconds": 1.000064325, - "uploadBytes": 0, - "downloadBytes": 171264000 - }, - { - "type": "intermediate", - "timeSeconds": 1.000091275, - "uploadBytes": 0, - "downloadBytes": 171417600 - }, - { - "type": "intermediate", - "timeSeconds": 1.000132241, - "uploadBytes": 0, - "downloadBytes": 170661888 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072835, - "uploadBytes": 0, - "downloadBytes": 167982080 - } - ], - "implementation": "rust-libp2p", - "version": "v0.55", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "intermediate", - "timeSeconds": 1.000089381, - "uploadBytes": 0, - "downloadBytes": 28587192 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077412, - "uploadBytes": 0, - "downloadBytes": 71494514 - }, - { - "type": "intermediate", - "timeSeconds": 1.000084773, - "uploadBytes": 0, - "downloadBytes": 71126226 - }, - { - "type": "intermediate", - "timeSeconds": 1.000051772, - "uploadBytes": 0, - "downloadBytes": 72254703 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077525, - "uploadBytes": 0, - "downloadBytes": 72707246 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072838, - "uploadBytes": 0, - "downloadBytes": 72522319 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080875, - "uploadBytes": 0, - "downloadBytes": 72773271 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081968, - "uploadBytes": 0, - "downloadBytes": 72312872 - }, - { - "type": "intermediate", - "timeSeconds": 1.000048589, - "uploadBytes": 0, - "downloadBytes": 72382444 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074432, - "uploadBytes": 0, - "downloadBytes": 72560409 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007232, - "uploadBytes": 0, - "downloadBytes": 72805766 - }, - { - "type": "intermediate", - "timeSeconds": 1.00006958, - "uploadBytes": 0, - "downloadBytes": 72466324 - }, - { - "type": "intermediate", - "timeSeconds": 1.000041419, - "uploadBytes": 0, - "downloadBytes": 71680795 - }, - { - "type": "intermediate", - "timeSeconds": 1.00006889, - "uploadBytes": 0, - "downloadBytes": 71391075 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075649, - "uploadBytes": 0, - "downloadBytes": 71187334 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078694, - "uploadBytes": 0, - "downloadBytes": 71550604 - }, - { - "type": "intermediate", - "timeSeconds": 1.000067456, - "uploadBytes": 0, - "downloadBytes": 71435934 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007308, - "uploadBytes": 0, - "downloadBytes": 71099932 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072091, - "uploadBytes": 0, - "downloadBytes": 71089512 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081417, - "uploadBytes": 0, - "downloadBytes": 28494183 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086788, - "uploadBytes": 0, - "downloadBytes": 71807087 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070723, - "uploadBytes": 0, - "downloadBytes": 72060939 - }, - { - "type": "intermediate", - "timeSeconds": 1.000068386, - "uploadBytes": 0, - "downloadBytes": 71507708 - }, - { - "type": "intermediate", - "timeSeconds": 1.000095395, - "uploadBytes": 0, - "downloadBytes": 71619427 - }, - { - "type": "intermediate", - "timeSeconds": 1.000093093, - "uploadBytes": 0, - "downloadBytes": 72013577 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080027, - "uploadBytes": 0, - "downloadBytes": 71402398 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075052, - "uploadBytes": 0, - "downloadBytes": 71838414 - }, - { - "type": "intermediate", - "timeSeconds": 1.0000699, - "uploadBytes": 0, - "downloadBytes": 71894666 - }, - { - "type": "intermediate", - "timeSeconds": 1.000068468, - "uploadBytes": 0, - "downloadBytes": 71720565 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077207, - "uploadBytes": 0, - "downloadBytes": 71549668 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078136, - "uploadBytes": 0, - "downloadBytes": 71971349 - }, - { - "type": "intermediate", - "timeSeconds": 1.000063792, - "uploadBytes": 0, - "downloadBytes": 72378226 - }, - { - "type": "intermediate", - "timeSeconds": 1.000085428, - "uploadBytes": 0, - "downloadBytes": 71991609 - }, - { - "type": "intermediate", - "timeSeconds": 1.000058639, - "uploadBytes": 0, - "downloadBytes": 71659083 - }, - { - "type": "intermediate", - "timeSeconds": 1.000065526, - "uploadBytes": 0, - "downloadBytes": 71786753 - }, - { - "type": "intermediate", - "timeSeconds": 1.000067791, - "uploadBytes": 0, - "downloadBytes": 71982073 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081971, - "uploadBytes": 0, - "downloadBytes": 72176462 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059909, - "uploadBytes": 0, - "downloadBytes": 71445073 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078879, - "uploadBytes": 0, - "downloadBytes": 28118654 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077756, - "uploadBytes": 0, - "downloadBytes": 71615123 - }, - { - "type": "intermediate", - "timeSeconds": 1.000069501, - "uploadBytes": 0, - "downloadBytes": 72209139 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079112, - "uploadBytes": 0, - "downloadBytes": 71870004 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070988, - "uploadBytes": 0, - "downloadBytes": 71217427 - }, - { - "type": "intermediate", - "timeSeconds": 1.000094179, - "uploadBytes": 0, - "downloadBytes": 71569593 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059723, - "uploadBytes": 0, - "downloadBytes": 71652854 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074659, - "uploadBytes": 0, - "downloadBytes": 72040776 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075608, - "uploadBytes": 0, - "downloadBytes": 71848367 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070245, - "uploadBytes": 0, - "downloadBytes": 71930050 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082999, - "uploadBytes": 0, - "downloadBytes": 72132734 - }, - { - "type": "intermediate", - "timeSeconds": 1.000067932, - "uploadBytes": 0, - "downloadBytes": 71175152 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080326, - "uploadBytes": 0, - "downloadBytes": 71060502 - }, - { - "type": "intermediate", - "timeSeconds": 1.000090937, - "uploadBytes": 0, - "downloadBytes": 70968843 - }, - { - "type": "intermediate", - "timeSeconds": 1.000057289, - "uploadBytes": 0, - "downloadBytes": 71856430 - }, - { - "type": "intermediate", - "timeSeconds": 1.00008656, - "uploadBytes": 0, - "downloadBytes": 71644734 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080673, - "uploadBytes": 0, - "downloadBytes": 71593951 - }, - { - "type": "intermediate", - "timeSeconds": 1.000084886, - "uploadBytes": 0, - "downloadBytes": 71131537 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007259, - "uploadBytes": 0, - "downloadBytes": 71963669 - }, - { - "type": "intermediate", - "timeSeconds": 1.00009395, - "uploadBytes": 0, - "downloadBytes": 28019398 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078395, - "uploadBytes": 0, - "downloadBytes": 71065069 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076967, - "uploadBytes": 0, - "downloadBytes": 71056367 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076686, - "uploadBytes": 0, - "downloadBytes": 70566080 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076243, - "uploadBytes": 0, - "downloadBytes": 70838732 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072516, - "uploadBytes": 0, - "downloadBytes": 70746320 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072437, - "uploadBytes": 0, - "downloadBytes": 71176228 - }, - { - "type": "intermediate", - "timeSeconds": 1.00005197, - "uploadBytes": 0, - "downloadBytes": 71262049 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081147, - "uploadBytes": 0, - "downloadBytes": 70921374 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076715, - "uploadBytes": 0, - "downloadBytes": 71128801 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078615, - "uploadBytes": 0, - "downloadBytes": 71149362 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070336, - "uploadBytes": 0, - "downloadBytes": 71341990 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086958, - "uploadBytes": 0, - "downloadBytes": 71172680 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081824, - "uploadBytes": 0, - "downloadBytes": 71051396 - }, - { - "type": "intermediate", - "timeSeconds": 1.000069482, - "uploadBytes": 0, - "downloadBytes": 70878208 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078397, - "uploadBytes": 0, - "downloadBytes": 70727680 - }, - { - "type": "intermediate", - "timeSeconds": 1.000092864, - "uploadBytes": 0, - "downloadBytes": 70036574 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007247, - "uploadBytes": 0, - "downloadBytes": 70765741 - }, - { - "type": "intermediate", - "timeSeconds": 1.000084589, - "uploadBytes": 0, - "downloadBytes": 70392528 - }, - { - "type": "intermediate", - "timeSeconds": 1.00010329, - "uploadBytes": 0, - "downloadBytes": 28253411 - }, - { - "type": "intermediate", - "timeSeconds": 1.000056356, - "uploadBytes": 0, - "downloadBytes": 72144456 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080473, - "uploadBytes": 0, - "downloadBytes": 72316367 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083254, - "uploadBytes": 0, - "downloadBytes": 72179415 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077943, - "uploadBytes": 0, - "downloadBytes": 72096445 - }, - { - "type": "intermediate", - "timeSeconds": 1.000084244, - "uploadBytes": 0, - "downloadBytes": 72521031 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080821, - "uploadBytes": 0, - "downloadBytes": 72447200 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074391, - "uploadBytes": 0, - "downloadBytes": 71807809 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076967, - "uploadBytes": 0, - "downloadBytes": 72144355 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077834, - "uploadBytes": 0, - "downloadBytes": 71468176 - }, - { - "type": "intermediate", - "timeSeconds": 1.000087319, - "uploadBytes": 0, - "downloadBytes": 72772401 - }, - { - "type": "intermediate", - "timeSeconds": 1.000064146, - "uploadBytes": 0, - "downloadBytes": 72101173 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059995, - "uploadBytes": 0, - "downloadBytes": 71789763 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073087, - "uploadBytes": 0, - "downloadBytes": 71912770 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072015, - "uploadBytes": 0, - "downloadBytes": 71674675 - }, - { - "type": "intermediate", - "timeSeconds": 1.000069763, - "uploadBytes": 0, - "downloadBytes": 72125284 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070612, - "uploadBytes": 0, - "downloadBytes": 71532034 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076061, - "uploadBytes": 0, - "downloadBytes": 71388199 - }, - { - "type": "intermediate", - "timeSeconds": 1.00005418, - "uploadBytes": 0, - "downloadBytes": 71269770 - }, - { - "type": "intermediate", - "timeSeconds": 1.000095861, - "uploadBytes": 0, - "downloadBytes": 28787838 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082335, - "uploadBytes": 0, - "downloadBytes": 71638242 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086742, - "uploadBytes": 0, - "downloadBytes": 71858498 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074862, - "uploadBytes": 0, - "downloadBytes": 72078275 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072865, - "uploadBytes": 0, - "downloadBytes": 71705863 - }, - { - "type": "intermediate", - "timeSeconds": 1.000085776, - "uploadBytes": 0, - "downloadBytes": 71299636 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083006, - "uploadBytes": 0, - "downloadBytes": 71335524 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083093, - "uploadBytes": 0, - "downloadBytes": 71994255 - }, - { - "type": "intermediate", - "timeSeconds": 1.000036074, - "uploadBytes": 0, - "downloadBytes": 72504124 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077829, - "uploadBytes": 0, - "downloadBytes": 72381999 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078258, - "uploadBytes": 0, - "downloadBytes": 72032850 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086306, - "uploadBytes": 0, - "downloadBytes": 71606735 - }, - { - "type": "intermediate", - "timeSeconds": 1.000063368, - "uploadBytes": 0, - "downloadBytes": 71785873 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007765, - "uploadBytes": 0, - "downloadBytes": 71880300 - }, - { - "type": "intermediate", - "timeSeconds": 1.000052294, - "uploadBytes": 0, - "downloadBytes": 71638145 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078861, - "uploadBytes": 0, - "downloadBytes": 71733419 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075324, - "uploadBytes": 0, - "downloadBytes": 71846133 - }, - { - "type": "intermediate", - "timeSeconds": 1.000064896, - "uploadBytes": 0, - "downloadBytes": 71571046 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073569, - "uploadBytes": 0, - "downloadBytes": 71671618 - }, - { - "type": "intermediate", - "timeSeconds": 1.000094456, - "uploadBytes": 0, - "downloadBytes": 30864113 - }, - { - "type": "intermediate", - "timeSeconds": 1.00006946, - "uploadBytes": 0, - "downloadBytes": 73172342 - }, - { - "type": "intermediate", - "timeSeconds": 1.000060061, - "uploadBytes": 0, - "downloadBytes": 73534844 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077595, - "uploadBytes": 0, - "downloadBytes": 71999322 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079349, - "uploadBytes": 0, - "downloadBytes": 73058356 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080254, - "uploadBytes": 0, - "downloadBytes": 73034698 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077107, - "uploadBytes": 0, - "downloadBytes": 73018097 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073504, - "uploadBytes": 0, - "downloadBytes": 73017417 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073768, - "uploadBytes": 0, - "downloadBytes": 72301457 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074436, - "uploadBytes": 0, - "downloadBytes": 72827214 - }, - { - "type": "intermediate", - "timeSeconds": 1.000059629, - "uploadBytes": 0, - "downloadBytes": 73108612 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073107, - "uploadBytes": 0, - "downloadBytes": 73031620 - }, - { - "type": "intermediate", - "timeSeconds": 1.000071312, - "uploadBytes": 0, - "downloadBytes": 72427253 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077014, - "uploadBytes": 0, - "downloadBytes": 73004684 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070364, - "uploadBytes": 0, - "downloadBytes": 72503977 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007767, - "uploadBytes": 0, - "downloadBytes": 73003679 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079176, - "uploadBytes": 0, - "downloadBytes": 73108304 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080758, - "uploadBytes": 0, - "downloadBytes": 73370589 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082076, - "uploadBytes": 0, - "downloadBytes": 71824309 - }, - { - "type": "intermediate", - "timeSeconds": 1.000086223, - "uploadBytes": 0, - "downloadBytes": 26539694 - }, - { - "type": "intermediate", - "timeSeconds": 1.00005822, - "uploadBytes": 0, - "downloadBytes": 71609939 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083089, - "uploadBytes": 0, - "downloadBytes": 71051272 - }, - { - "type": "intermediate", - "timeSeconds": 1.000065087, - "uploadBytes": 0, - "downloadBytes": 70992785 - }, - { - "type": "intermediate", - "timeSeconds": 1.000096079, - "uploadBytes": 0, - "downloadBytes": 72021278 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077542, - "uploadBytes": 0, - "downloadBytes": 71091244 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007682, - "uploadBytes": 0, - "downloadBytes": 71498235 - }, - { - "type": "intermediate", - "timeSeconds": 1.000071884, - "uploadBytes": 0, - "downloadBytes": 71350043 - }, - { - "type": "intermediate", - "timeSeconds": 1.000074441, - "uploadBytes": 0, - "downloadBytes": 71276515 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075269, - "uploadBytes": 0, - "downloadBytes": 71191086 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080254, - "uploadBytes": 0, - "downloadBytes": 71040342 - }, - { - "type": "intermediate", - "timeSeconds": 1.00006945, - "uploadBytes": 0, - "downloadBytes": 71174136 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070683, - "uploadBytes": 0, - "downloadBytes": 71275366 - }, - { - "type": "intermediate", - "timeSeconds": 1.000083002, - "uploadBytes": 0, - "downloadBytes": 70081380 - }, - { - "type": "intermediate", - "timeSeconds": 1.000035902, - "uploadBytes": 0, - "downloadBytes": 70885579 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073922, - "uploadBytes": 0, - "downloadBytes": 71577173 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077679, - "uploadBytes": 0, - "downloadBytes": 71895328 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079935, - "uploadBytes": 0, - "downloadBytes": 71695510 - }, - { - "type": "intermediate", - "timeSeconds": 1.000067933, - "uploadBytes": 0, - "downloadBytes": 71834519 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082968, - "uploadBytes": 0, - "downloadBytes": 28243066 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076578, - "uploadBytes": 0, - "downloadBytes": 72065534 - }, - { - "type": "intermediate", - "timeSeconds": 1.000071632, - "uploadBytes": 0, - "downloadBytes": 71540442 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081877, - "uploadBytes": 0, - "downloadBytes": 71776179 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073261, - "uploadBytes": 0, - "downloadBytes": 72064738 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078653, - "uploadBytes": 0, - "downloadBytes": 72021971 - }, - { - "type": "intermediate", - "timeSeconds": 1.000056753, - "uploadBytes": 0, - "downloadBytes": 71953233 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078425, - "uploadBytes": 0, - "downloadBytes": 71785561 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078095, - "uploadBytes": 0, - "downloadBytes": 71801926 - }, - { - "type": "intermediate", - "timeSeconds": 1.000079547, - "uploadBytes": 0, - "downloadBytes": 71931998 - }, - { - "type": "intermediate", - "timeSeconds": 1.000080615, - "uploadBytes": 0, - "downloadBytes": 71663114 - }, - { - "type": "intermediate", - "timeSeconds": 1.000066133, - "uploadBytes": 0, - "downloadBytes": 71451158 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007787, - "uploadBytes": 0, - "downloadBytes": 71255017 - }, - { - "type": "intermediate", - "timeSeconds": 1.000065635, - "uploadBytes": 0, - "downloadBytes": 71427247 - }, - { - "type": "intermediate", - "timeSeconds": 1.000048128, - "uploadBytes": 0, - "downloadBytes": 71461029 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073571, - "uploadBytes": 0, - "downloadBytes": 71458261 - }, - { - "type": "intermediate", - "timeSeconds": 1.000081972, - "uploadBytes": 0, - "downloadBytes": 71409061 - }, - { - "type": "intermediate", - "timeSeconds": 1.000070496, - "uploadBytes": 0, - "downloadBytes": 71050976 - }, - { - "type": "intermediate", - "timeSeconds": 1.000071618, - "uploadBytes": 0, - "downloadBytes": 71303257 - }, - { - "type": "intermediate", - "timeSeconds": 1.000082359, - "uploadBytes": 0, - "downloadBytes": 29897598 - }, - { - "type": "intermediate", - "timeSeconds": 1.000078193, - "uploadBytes": 0, - "downloadBytes": 73313722 - }, - { - "type": "intermediate", - "timeSeconds": 1.000091535, - "uploadBytes": 0, - "downloadBytes": 72759231 - }, - { - "type": "intermediate", - "timeSeconds": 1.000073601, - "uploadBytes": 0, - "downloadBytes": 72710444 - }, - { - "type": "intermediate", - "timeSeconds": 1.000087308, - "uploadBytes": 0, - "downloadBytes": 73142541 - }, - { - "type": "intermediate", - "timeSeconds": 1.000028519, - "uploadBytes": 0, - "downloadBytes": 72618029 - }, - { - "type": "intermediate", - "timeSeconds": 1.000056699, - "uploadBytes": 0, - "downloadBytes": 71896863 - }, - { - "type": "intermediate", - "timeSeconds": 1.000072311, - "uploadBytes": 0, - "downloadBytes": 72540197 - }, - { - "type": "intermediate", - "timeSeconds": 1.000077544, - "uploadBytes": 0, - "downloadBytes": 73004370 - }, - { - "type": "intermediate", - "timeSeconds": 1.000098528, - "uploadBytes": 0, - "downloadBytes": 73017488 - }, - { - "type": "intermediate", - "timeSeconds": 1.000065924, - "uploadBytes": 0, - "downloadBytes": 73060386 - }, - { - "type": "intermediate", - "timeSeconds": 1.000053897, - "uploadBytes": 0, - "downloadBytes": 73084222 - }, - { - "type": "intermediate", - "timeSeconds": 1.000062445, - "uploadBytes": 0, - "downloadBytes": 73023444 - }, - { - "type": "intermediate", - "timeSeconds": 1.000085291, - "uploadBytes": 0, - "downloadBytes": 72555349 - }, - { - "type": "intermediate", - "timeSeconds": 1.000050607, - "uploadBytes": 0, - "downloadBytes": 72621275 - }, - { - "type": "intermediate", - "timeSeconds": 1.000068877, - "uploadBytes": 0, - "downloadBytes": 73055205 - }, - { - "type": "intermediate", - "timeSeconds": 1.000076626, - "uploadBytes": 0, - "downloadBytes": 72827442 - }, - { - "type": "intermediate", - "timeSeconds": 1.000075504, - "uploadBytes": 0, - "downloadBytes": 72802612 - }, - { - "type": "intermediate", - "timeSeconds": 1.00007946, - "uploadBytes": 0, - "downloadBytes": 73023814 - } - ], - "implementation": "rust-libp2p", - "version": "v0.55", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.000071694, - "uploadBytes": 0, - "downloadBytes": 166109184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000092739, - "uploadBytes": 0, - "downloadBytes": 597311488 - }, - { - "type": "intermediary", - "timeSeconds": 1.000082247, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000161958, - "uploadBytes": 0, - "downloadBytes": 597311488 - }, - { - "type": "intermediary", - "timeSeconds": 1.000143603, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000085834, - "uploadBytes": 0, - "downloadBytes": 588791808 - }, - { - "type": "intermediary", - "timeSeconds": 1.000082532, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.00009819, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000092416, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000014211, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000028, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000069229, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000040562, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000084, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000141609, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000080678, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000033483, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000149845, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004988, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000026464, - "uploadBytes": 0, - "downloadBytes": 162488320 - }, - { - "type": "intermediary", - "timeSeconds": 1.000006563, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004922, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000336658, - "uploadBytes": 0, - "downloadBytes": 556924928 - }, - { - "type": "intermediary", - "timeSeconds": 1.000283542, - "uploadBytes": 0, - "downloadBytes": 504938496 - }, - { - "type": "intermediary", - "timeSeconds": 1.000222524, - "uploadBytes": 0, - "downloadBytes": 487882752 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005452, - "uploadBytes": 0, - "downloadBytes": 502792192 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031122, - "uploadBytes": 0, - "downloadBytes": 525205504 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010097, - "uploadBytes": 0, - "downloadBytes": 540131328 - }, - { - "type": "intermediary", - "timeSeconds": 1.000050949, - "uploadBytes": 0, - "downloadBytes": 554385408 - }, - { - "type": "intermediary", - "timeSeconds": 1.000079092, - "uploadBytes": 0, - "downloadBytes": 567164928 - }, - { - "type": "intermediary", - "timeSeconds": 1.000217612, - "uploadBytes": 0, - "downloadBytes": 578797568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072916, - "uploadBytes": 0, - "downloadBytes": 588398592 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008815, - "uploadBytes": 0, - "downloadBytes": 596295680 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010791, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000186866, - "uploadBytes": 0, - "downloadBytes": 597311488 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002353, - "uploadBytes": 0, - "downloadBytes": 597344256 - }, - { - "type": "intermediary", - "timeSeconds": 1.000056853, - "uploadBytes": 0, - "downloadBytes": 597147648 - }, - { - "type": "intermediary", - "timeSeconds": 1.000124361, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000035169, - "uploadBytes": 0, - "downloadBytes": 162881536 - }, - { - "type": "intermediary", - "timeSeconds": 1.000250895, - "uploadBytes": 0, - "downloadBytes": 274382848 - }, - { - "type": "intermediary", - "timeSeconds": 1.000344227, - "uploadBytes": 0, - "downloadBytes": 249823232 - }, - { - "type": "intermediary", - "timeSeconds": 1.000870065, - "uploadBytes": 0, - "downloadBytes": 258867200 - }, - { - "type": "intermediary", - "timeSeconds": 1.000043154, - "uploadBytes": 0, - "downloadBytes": 265830400 - }, - { - "type": "intermediary", - "timeSeconds": 1.000056701, - "uploadBytes": 0, - "downloadBytes": 207159296 - }, - { - "type": "intermediary", - "timeSeconds": 1.000246036, - "uploadBytes": 0, - "downloadBytes": 196100096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000839473, - "uploadBytes": 0, - "downloadBytes": 203653120 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000613, - "uploadBytes": 0, - "downloadBytes": 207372288 - }, - { - "type": "intermediary", - "timeSeconds": 1.00015147, - "uploadBytes": 0, - "downloadBytes": 210780160 - }, - { - "type": "intermediary", - "timeSeconds": 1.000257687, - "uploadBytes": 0, - "downloadBytes": 215089152 - }, - { - "type": "intermediary", - "timeSeconds": 1.000757441, - "uploadBytes": 0, - "downloadBytes": 220692480 - }, - { - "type": "intermediary", - "timeSeconds": 1.000094673, - "uploadBytes": 0, - "downloadBytes": 220413952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000441054, - "uploadBytes": 0, - "downloadBytes": 222576640 - }, - { - "type": "intermediary", - "timeSeconds": 1.000016883, - "uploadBytes": 0, - "downloadBytes": 224591872 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017028, - "uploadBytes": 0, - "downloadBytes": 227737600 - }, - { - "type": "intermediary", - "timeSeconds": 1.000152353, - "uploadBytes": 0, - "downloadBytes": 225869824 - }, - { - "type": "intermediary", - "timeSeconds": 1.000426975, - "uploadBytes": 0, - "downloadBytes": 175095808 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011089, - "uploadBytes": 0, - "downloadBytes": 167329792 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013098, - "uploadBytes": 0, - "downloadBytes": 202711040 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000016, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002057, - "uploadBytes": 0, - "downloadBytes": 567230464 - }, - { - "type": "intermediary", - "timeSeconds": 1.000100522, - "uploadBytes": 0, - "downloadBytes": 531136512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000149, - "uploadBytes": 0, - "downloadBytes": 552124416 - }, - { - "type": "intermediary", - "timeSeconds": 1.000095702, - "uploadBytes": 0, - "downloadBytes": 570523648 - }, - { - "type": "intermediary", - "timeSeconds": 1.000155486, - "uploadBytes": 0, - "downloadBytes": 588316672 - }, - { - "type": "intermediary", - "timeSeconds": 1.00016589, - "uploadBytes": 0, - "downloadBytes": 579584000 - }, - { - "type": "intermediary", - "timeSeconds": 1.000023767, - "uploadBytes": 0, - "downloadBytes": 434733056 - }, - { - "type": "intermediary", - "timeSeconds": 1.000122053, - "uploadBytes": 0, - "downloadBytes": 445677568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000060835, - "uploadBytes": 0, - "downloadBytes": 455475200 - }, - { - "type": "intermediary", - "timeSeconds": 1.000199632, - "uploadBytes": 0, - "downloadBytes": 464470016 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013407, - "uploadBytes": 0, - "downloadBytes": 473104384 - }, - { - "type": "intermediary", - "timeSeconds": 1.00007253, - "uploadBytes": 0, - "downloadBytes": 358547456 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000551, - "uploadBytes": 0, - "downloadBytes": 257687552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000153318, - "uploadBytes": 0, - "downloadBytes": 252280832 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003603, - "uploadBytes": 0, - "downloadBytes": 259014656 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008718, - "uploadBytes": 0, - "downloadBytes": 265338880 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000296, - "uploadBytes": 0, - "downloadBytes": 270999552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019582, - "uploadBytes": 0, - "downloadBytes": 86138880 - }, - { - "type": "intermediary", - "timeSeconds": 1.000014593, - "uploadBytes": 0, - "downloadBytes": 207208448 - }, - { - "type": "intermediary", - "timeSeconds": 1.000058706, - "uploadBytes": 0, - "downloadBytes": 218021888 - }, - { - "type": "intermediary", - "timeSeconds": 1.00092916, - "uploadBytes": 0, - "downloadBytes": 204849152 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003932, - "uploadBytes": 0, - "downloadBytes": 165380096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000140697, - "uploadBytes": 0, - "downloadBytes": 169820160 - }, - { - "type": "intermediary", - "timeSeconds": 1.000542646, - "uploadBytes": 0, - "downloadBytes": 174178304 - }, - { - "type": "intermediary", - "timeSeconds": 1.000089237, - "uploadBytes": 0, - "downloadBytes": 178208768 - }, - { - "type": "intermediary", - "timeSeconds": 1.002291244, - "uploadBytes": 0, - "downloadBytes": 182059008 - }, - { - "type": "intermediary", - "timeSeconds": 1.001206581, - "uploadBytes": 0, - "downloadBytes": 185237504 - }, - { - "type": "intermediary", - "timeSeconds": 1.000001237, - "uploadBytes": 0, - "downloadBytes": 188055552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000225335, - "uploadBytes": 0, - "downloadBytes": 191021056 - }, - { - "type": "intermediary", - "timeSeconds": 1.000312862, - "uploadBytes": 0, - "downloadBytes": 191479808 - }, - { - "type": "intermediary", - "timeSeconds": 1.000100581, - "uploadBytes": 0, - "downloadBytes": 192593920 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008421, - "uploadBytes": 0, - "downloadBytes": 149946368 - }, - { - "type": "intermediary", - "timeSeconds": 1.000087835, - "uploadBytes": 0, - "downloadBytes": 143310848 - }, - { - "type": "intermediary", - "timeSeconds": 1.000400043, - "uploadBytes": 0, - "downloadBytes": 149143552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000408242, - "uploadBytes": 0, - "downloadBytes": 151355392 - }, - { - "type": "intermediary", - "timeSeconds": 1.000047729, - "uploadBytes": 0, - "downloadBytes": 154009600 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000273, - "uploadBytes": 0, - "downloadBytes": 200548352 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000071, - "uploadBytes": 0, - "downloadBytes": 597180416 - }, - { - "type": "intermediary", - "timeSeconds": 1.000104152, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010763, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019502, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000032224, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000143859, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002594, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000101348, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000179866, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000001758, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000057, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000434, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000047731, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000129103, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000066343, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000146934, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000375, - "uploadBytes": 0, - "downloadBytes": 597344256 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000676, - "uploadBytes": 0, - "downloadBytes": 597180416 - }, - { - "type": "intermediary", - "timeSeconds": 1.00001633, - "uploadBytes": 0, - "downloadBytes": 135602176 - }, - { - "type": "intermediary", - "timeSeconds": 1.000007458, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005664, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000169, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027458, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000022087, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010575, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000184, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000025282, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000033021, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000671, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000025788, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000042422, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000451, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009448, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000050092, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000038387, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000014513, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020694, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000070434, - "uploadBytes": 0, - "downloadBytes": 95133696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000171463, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000007669, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000100199, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000093527, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000138928, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000180455, - "uploadBytes": 0, - "downloadBytes": 597327872 - }, - { - "type": "intermediary", - "timeSeconds": 1.000012846, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011204, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000022234, - "uploadBytes": 0, - "downloadBytes": 582696960 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009244, - "uploadBytes": 0, - "downloadBytes": 580239360 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005434, - "uploadBytes": 0, - "downloadBytes": 596361216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000069218, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002076, - "uploadBytes": 0, - "downloadBytes": 471908352 - }, - { - "type": "intermediary", - "timeSeconds": 1.000426153, - "uploadBytes": 0, - "downloadBytes": 443170816 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005865, - "uploadBytes": 0, - "downloadBytes": 353517568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003916, - "uploadBytes": 0, - "downloadBytes": 328810496 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000092, - "uploadBytes": 0, - "downloadBytes": 338231296 - }, - { - "type": "intermediary", - "timeSeconds": 1.000070535, - "uploadBytes": 0, - "downloadBytes": 344801280 - }, - { - "type": "intermediary", - "timeSeconds": 1.000051334, - "uploadBytes": 0, - "downloadBytes": 175628288 - }, - { - "type": "intermediary", - "timeSeconds": 1.000037584, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000059433, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000053335, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000682, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019509, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004549, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000012505, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000033503, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000418, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000024258, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000033, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000074662, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000030236, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003208, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000056664, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000029943, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000041122, - "uploadBytes": 0, - "downloadBytes": 597262336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000862, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003458, - "uploadBytes": 0, - "downloadBytes": 153001984 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000923, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000086552, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000028533, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000023843, - "uploadBytes": 0, - "downloadBytes": 597213184 - }, - { - "type": "intermediary", - "timeSeconds": 1.00015733, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000157564, - "uploadBytes": 0, - "downloadBytes": 597327872 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003413, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000048777, - "uploadBytes": 0, - "downloadBytes": 597196800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000156372, - "uploadBytes": 0, - "downloadBytes": 597295104 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011829, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000160965, - "uploadBytes": 0, - "downloadBytes": 597278720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000007083, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000059687, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000032268, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.00002382, - "uploadBytes": 0, - "downloadBytes": 597229568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000039079, - "uploadBytes": 0, - "downloadBytes": 597245952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000154367, - "uploadBytes": 0, - "downloadBytes": 597311488 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010288, - "uploadBytes": 0, - "downloadBytes": 597245952 - } - ], - "implementation": "https", - "version": "v0.1", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.034652289, - "uploadBytes": 0, - "downloadBytes": 8388608 - }, - { - "type": "intermediary", - "timeSeconds": 1.010825107, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.034078775, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.036285039, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.036557048, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004035, - "uploadBytes": 0, - "downloadBytes": 106635264 - }, - { - "type": "intermediary", - "timeSeconds": 1.01245716, - "uploadBytes": 0, - "downloadBytes": 103079936 - }, - { - "type": "intermediary", - "timeSeconds": 1.036970045, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.035232092, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.041479932, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054429612, - "uploadBytes": 0, - "downloadBytes": 83886080 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072316, - "uploadBytes": 0, - "downloadBytes": 68165632 - }, - { - "type": "intermediary", - "timeSeconds": 1.00002015, - "uploadBytes": 0, - "downloadBytes": 70451200 - }, - { - "type": "intermediary", - "timeSeconds": 1.04781956, - "uploadBytes": 0, - "downloadBytes": 69074944 - }, - { - "type": "intermediary", - "timeSeconds": 1.058187873, - "uploadBytes": 0, - "downloadBytes": 69132288 - }, - { - "type": "intermediary", - "timeSeconds": 1.000094367, - "uploadBytes": 0, - "downloadBytes": 71835648 - }, - { - "type": "intermediary", - "timeSeconds": 1.045108648, - "uploadBytes": 0, - "downloadBytes": 69074944 - }, - { - "type": "intermediary", - "timeSeconds": 1.054469724, - "uploadBytes": 0, - "downloadBytes": 68804608 - }, - { - "type": "intermediary", - "timeSeconds": 1.000021553, - "uploadBytes": 0, - "downloadBytes": 73801728 - }, - { - "type": "intermediary", - "timeSeconds": 1.046984525, - "uploadBytes": 0, - "downloadBytes": 33685504 - }, - { - "type": "intermediary", - "timeSeconds": 1.058170158, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.056074091, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058206608, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058929079, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.057812237, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058579656, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058138438, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059078299, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058059596, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.061733887, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058524944, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.060144421, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058347113, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.057028092, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027031, - "uploadBytes": 0, - "downloadBytes": 117055488 - }, - { - "type": "intermediary", - "timeSeconds": 1.051109765, - "uploadBytes": 0, - "downloadBytes": 109436928 - }, - { - "type": "intermediary", - "timeSeconds": 1.05586651, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.026726708, - "uploadBytes": 0, - "downloadBytes": 8388608 - }, - { - "type": "intermediary", - "timeSeconds": 1.059184282, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.006566646, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.006962398, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.005361462, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.007612251, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.007209936, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.006677693, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.009003561, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004755239, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.005557677, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004867191, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.006984558, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.036735526, - "uploadBytes": 0, - "downloadBytes": 93790208 - }, - { - "type": "intermediary", - "timeSeconds": 1.05431642, - "uploadBytes": 0, - "downloadBytes": 61472768 - }, - { - "type": "intermediary", - "timeSeconds": 1.010526203, - "uploadBytes": 0, - "downloadBytes": 62840832 - }, - { - "type": "intermediary", - "timeSeconds": 1.004842502, - "uploadBytes": 0, - "downloadBytes": 63184896 - }, - { - "type": "intermediary", - "timeSeconds": 1.007917979, - "uploadBytes": 0, - "downloadBytes": 62644224 - }, - { - "type": "intermediary", - "timeSeconds": 1.001240283, - "uploadBytes": 0, - "downloadBytes": 63315968 - }, - { - "type": "intermediary", - "timeSeconds": 1.05449647, - "uploadBytes": 0, - "downloadBytes": 33554432 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031409, - "uploadBytes": 0, - "downloadBytes": 113123328 - }, - { - "type": "intermediary", - "timeSeconds": 1.062430297, - "uploadBytes": 0, - "downloadBytes": 113369088 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000345, - "uploadBytes": 0, - "downloadBytes": 112812032 - }, - { - "type": "intermediary", - "timeSeconds": 1.000091903, - "uploadBytes": 0, - "downloadBytes": 112640000 - }, - { - "type": "intermediary", - "timeSeconds": 1.058424534, - "uploadBytes": 0, - "downloadBytes": 110092288 - }, - { - "type": "intermediary", - "timeSeconds": 1.000087651, - "uploadBytes": 0, - "downloadBytes": 115417088 - }, - { - "type": "intermediary", - "timeSeconds": 1.058297085, - "uploadBytes": 0, - "downloadBytes": 111075328 - }, - { - "type": "intermediary", - "timeSeconds": 1.054188625, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000468, - "uploadBytes": 0, - "downloadBytes": 112320512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000034858, - "uploadBytes": 0, - "downloadBytes": 112017408 - }, - { - "type": "intermediary", - "timeSeconds": 1.058326221, - "uploadBytes": 0, - "downloadBytes": 111206400 - }, - { - "type": "intermediary", - "timeSeconds": 1.00016508, - "uploadBytes": 0, - "downloadBytes": 115286016 - }, - { - "type": "intermediary", - "timeSeconds": 1.058769495, - "uploadBytes": 0, - "downloadBytes": 111206400 - }, - { - "type": "intermediary", - "timeSeconds": 1.000078466, - "uploadBytes": 0, - "downloadBytes": 112992256 - }, - { - "type": "intermediary", - "timeSeconds": 1.061459204, - "uploadBytes": 0, - "downloadBytes": 113500160 - }, - { - "type": "intermediary", - "timeSeconds": 1.00010533, - "uploadBytes": 0, - "downloadBytes": 111878144 - }, - { - "type": "intermediary", - "timeSeconds": 1.000039708, - "uploadBytes": 0, - "downloadBytes": 113704960 - }, - { - "type": "intermediary", - "timeSeconds": 1.058880913, - "uploadBytes": 0, - "downloadBytes": 109961216 - }, - { - "type": "intermediary", - "timeSeconds": 1.012426371, - "uploadBytes": 0, - "downloadBytes": 8069120 - }, - { - "type": "intermediary", - "timeSeconds": 1.034435978, - "uploadBytes": 0, - "downloadBytes": 100982784 - }, - { - "type": "intermediary", - "timeSeconds": 1.000043902, - "uploadBytes": 0, - "downloadBytes": 109780992 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003594, - "uploadBytes": 0, - "downloadBytes": 111476736 - }, - { - "type": "intermediary", - "timeSeconds": 1.04970971, - "uploadBytes": 0, - "downloadBytes": 105897984 - }, - { - "type": "intermediary", - "timeSeconds": 1.000052306, - "uploadBytes": 0, - "downloadBytes": 113516544 - }, - { - "type": "intermediary", - "timeSeconds": 1.000024634, - "uploadBytes": 0, - "downloadBytes": 110944256 - }, - { - "type": "intermediary", - "timeSeconds": 1.061878084, - "uploadBytes": 0, - "downloadBytes": 111083520 - }, - { - "type": "intermediary", - "timeSeconds": 1.000168594, - "uploadBytes": 0, - "downloadBytes": 112926720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020432, - "uploadBytes": 0, - "downloadBytes": 111607808 - }, - { - "type": "intermediary", - "timeSeconds": 1.062906226, - "uploadBytes": 0, - "downloadBytes": 111009792 - }, - { - "type": "intermediary", - "timeSeconds": 1.000022905, - "uploadBytes": 0, - "downloadBytes": 111026176 - }, - { - "type": "intermediary", - "timeSeconds": 1.000045267, - "uploadBytes": 0, - "downloadBytes": 114032640 - }, - { - "type": "intermediary", - "timeSeconds": 1.061859602, - "uploadBytes": 0, - "downloadBytes": 110485504 - }, - { - "type": "intermediary", - "timeSeconds": 1.000047679, - "uploadBytes": 0, - "downloadBytes": 112599040 - }, - { - "type": "intermediary", - "timeSeconds": 1.000083466, - "uploadBytes": 0, - "downloadBytes": 113639424 - }, - { - "type": "intermediary", - "timeSeconds": 1.0607992450000001, - "uploadBytes": 0, - "downloadBytes": 109305856 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000402, - "uploadBytes": 0, - "downloadBytes": 112476160 - }, - { - "type": "intermediary", - "timeSeconds": 1.062177804, - "uploadBytes": 0, - "downloadBytes": 114016256 - }, - { - "type": "intermediary", - "timeSeconds": 1.020118029, - "uploadBytes": 0, - "downloadBytes": 8388608 - }, - { - "type": "intermediary", - "timeSeconds": 1.052437577, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000879121, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.002194045, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.002815501, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.001750961, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000127874, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011597, - "uploadBytes": 0, - "downloadBytes": 110436352 - }, - { - "type": "intermediary", - "timeSeconds": 1.001055073, - "uploadBytes": 0, - "downloadBytes": 107667456 - }, - { - "type": "intermediary", - "timeSeconds": 1.00227164, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000192297, - "uploadBytes": 0, - "downloadBytes": 109191168 - }, - { - "type": "intermediary", - "timeSeconds": 1.000042041, - "uploadBytes": 0, - "downloadBytes": 111149056 - }, - { - "type": "intermediary", - "timeSeconds": 1.000116078, - "uploadBytes": 0, - "downloadBytes": 110493696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000025529, - "uploadBytes": 0, - "downloadBytes": 107151360 - }, - { - "type": "intermediary", - "timeSeconds": 1.000036776, - "uploadBytes": 0, - "downloadBytes": 110886912 - }, - { - "type": "intermediary", - "timeSeconds": 1.000095308, - "uploadBytes": 0, - "downloadBytes": 109707264 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011241, - "uploadBytes": 0, - "downloadBytes": 107937792 - }, - { - "type": "intermediary", - "timeSeconds": 1.000052688, - "uploadBytes": 0, - "downloadBytes": 108527616 - }, - { - "type": "intermediary", - "timeSeconds": 1.000130572, - "uploadBytes": 0, - "downloadBytes": 109314048 - }, - { - "type": "intermediary", - "timeSeconds": 1.01095431, - "uploadBytes": 0, - "downloadBytes": 25165824 - }, - { - "type": "intermediary", - "timeSeconds": 1.059196401, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.060671208, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059771453, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.061920979, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058137449, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.060211585, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059098506, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.060681883, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059016946, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.060070012, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.060005675, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.05843698, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058926336, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.05962043, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058867888, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054950306, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.057233206, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000069788, - "uploadBytes": 0, - "downloadBytes": 19144704 - }, - { - "type": "intermediary", - "timeSeconds": 1.051199507, - "uploadBytes": 0, - "downloadBytes": 115204096 - }, - { - "type": "intermediary", - "timeSeconds": 1.051454148, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.050449542, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.051945506, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.052420672, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.056972538, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.053198067, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054506297, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.051193571, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054141502, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.05504996, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.050743914, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.05656551, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055005829, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.056521531, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059320937, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055162582, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000070154, - "uploadBytes": 0, - "downloadBytes": 35594240 - }, - { - "type": "intermediary", - "timeSeconds": 1.0094833, - "uploadBytes": 0, - "downloadBytes": 107012096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000148984, - "uploadBytes": 0, - "downloadBytes": 100663296 - }, - { - "type": "intermediary", - "timeSeconds": 1.000319341, - "uploadBytes": 0, - "downloadBytes": 100663296 - }, - { - "type": "intermediary", - "timeSeconds": 1.012041283, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.007949478, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.012448108, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.010352581, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.008561586, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.011275793, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.011432156, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.007911482, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.010808751, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.008807851, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.015222985, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.010742448, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.010751953, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.01357028, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.009467879, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.021469216, - "uploadBytes": 0, - "downloadBytes": 25296896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000054336, - "uploadBytes": 0, - "downloadBytes": 113582080 - }, - { - "type": "intermediary", - "timeSeconds": 1.000007012, - "uploadBytes": 0, - "downloadBytes": 112656384 - }, - { - "type": "intermediary", - "timeSeconds": 1.060606548, - "uploadBytes": 0, - "downloadBytes": 109305856 - }, - { - "type": "intermediary", - "timeSeconds": 1.000062562, - "uploadBytes": 0, - "downloadBytes": 115679232 - }, - { - "type": "intermediary", - "timeSeconds": 1.06149811, - "uploadBytes": 0, - "downloadBytes": 110813184 - }, - { - "type": "intermediary", - "timeSeconds": 1.036369734, - "uploadBytes": 0, - "downloadBytes": 100663296 - }, - { - "type": "intermediary", - "timeSeconds": 1.000121984, - "uploadBytes": 0, - "downloadBytes": 115023872 - }, - { - "type": "intermediary", - "timeSeconds": 1.059127566, - "uploadBytes": 0, - "downloadBytes": 111468544 - }, - { - "type": "intermediary", - "timeSeconds": 1.000036499, - "uploadBytes": 0, - "downloadBytes": 110567424 - }, - { - "type": "intermediary", - "timeSeconds": 1.000050532, - "uploadBytes": 0, - "downloadBytes": 115146752 - }, - { - "type": "intermediary", - "timeSeconds": 1.000030046, - "uploadBytes": 0, - "downloadBytes": 109117440 - }, - { - "type": "intermediary", - "timeSeconds": 1.059001347, - "uploadBytes": 0, - "downloadBytes": 109764608 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000646, - "uploadBytes": 0, - "downloadBytes": 115351552 - }, - { - "type": "intermediary", - "timeSeconds": 1.059718484, - "uploadBytes": 0, - "downloadBytes": 111140864 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000631, - "uploadBytes": 0, - "downloadBytes": 113647616 - }, - { - "type": "intermediary", - "timeSeconds": 1.0600697590000001, - "uploadBytes": 0, - "downloadBytes": 112844800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005749, - "uploadBytes": 0, - "downloadBytes": 113385472 - }, - { - "type": "intermediary", - "timeSeconds": 1.059110978, - "uploadBytes": 0, - "downloadBytes": 113106944 - } - ], - "implementation": "go-libp2p", - "version": "v0.41", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.003285797, - "uploadBytes": 0, - "downloadBytes": 50110816 - }, - { - "type": "intermediary", - "timeSeconds": 1.000212424, - "uploadBytes": 0, - "downloadBytes": 110686836 - }, - { - "type": "intermediary", - "timeSeconds": 1.000177318, - "uploadBytes": 0, - "downloadBytes": 108241468 - }, - { - "type": "intermediary", - "timeSeconds": 1.000423801, - "uploadBytes": 0, - "downloadBytes": 108322816 - }, - { - "type": "intermediary", - "timeSeconds": 1.00002161, - "uploadBytes": 0, - "downloadBytes": 108498512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000081821, - "uploadBytes": 0, - "downloadBytes": 108737212 - }, - { - "type": "intermediary", - "timeSeconds": 1.000224157, - "uploadBytes": 0, - "downloadBytes": 109027900 - }, - { - "type": "intermediary", - "timeSeconds": 1.000193893, - "uploadBytes": 0, - "downloadBytes": 109245408 - }, - { - "type": "intermediary", - "timeSeconds": 1.000058785, - "uploadBytes": 0, - "downloadBytes": 109450768 - }, - { - "type": "intermediary", - "timeSeconds": 1.000038672, - "uploadBytes": 0, - "downloadBytes": 109593136 - }, - { - "type": "intermediary", - "timeSeconds": 1.000163088, - "uploadBytes": 0, - "downloadBytes": 109814536 - }, - { - "type": "intermediary", - "timeSeconds": 1.000001042, - "uploadBytes": 0, - "downloadBytes": 109988608 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018982, - "uploadBytes": 0, - "downloadBytes": 110133888 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000393, - "uploadBytes": 0, - "downloadBytes": 110496768 - }, - { - "type": "intermediary", - "timeSeconds": 1.000087602, - "uploadBytes": 0, - "downloadBytes": 110836608 - }, - { - "type": "intermediary", - "timeSeconds": 1.000025618, - "uploadBytes": 0, - "downloadBytes": 110919296 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020634, - "uploadBytes": 0, - "downloadBytes": 111104256 - }, - { - "type": "intermediary", - "timeSeconds": 1.000199075, - "uploadBytes": 0, - "downloadBytes": 111181169 - }, - { - "type": "intermediary", - "timeSeconds": 1.000192985, - "uploadBytes": 0, - "downloadBytes": 111427727 - }, - { - "type": "intermediary", - "timeSeconds": 1.000075337, - "uploadBytes": 0, - "downloadBytes": 56061086 - }, - { - "type": "intermediary", - "timeSeconds": 1.000052247, - "uploadBytes": 0, - "downloadBytes": 79528067 - }, - { - "type": "intermediary", - "timeSeconds": 1.000271045, - "uploadBytes": 0, - "downloadBytes": 76942099 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010954, - "uploadBytes": 0, - "downloadBytes": 76531928 - }, - { - "type": "intermediary", - "timeSeconds": 1.000015998, - "uploadBytes": 0, - "downloadBytes": 77073160 - }, - { - "type": "intermediary", - "timeSeconds": 1.000016368, - "uploadBytes": 0, - "downloadBytes": 77570620 - }, - { - "type": "intermediary", - "timeSeconds": 1.000510721, - "uploadBytes": 0, - "downloadBytes": 77894064 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000841, - "uploadBytes": 0, - "downloadBytes": 77989252 - }, - { - "type": "intermediary", - "timeSeconds": 1.000101202, - "uploadBytes": 0, - "downloadBytes": 78342348 - }, - { - "type": "intermediary", - "timeSeconds": 1.000181749, - "uploadBytes": 0, - "downloadBytes": 78597432 - }, - { - "type": "intermediary", - "timeSeconds": 1.00013008, - "uploadBytes": 0, - "downloadBytes": 78638669 - }, - { - "type": "intermediary", - "timeSeconds": 1.000149518, - "uploadBytes": 0, - "downloadBytes": 78899991 - }, - { - "type": "intermediary", - "timeSeconds": 1.000260186, - "uploadBytes": 0, - "downloadBytes": 79254189 - }, - { - "type": "intermediary", - "timeSeconds": 1.000096722, - "uploadBytes": 0, - "downloadBytes": 79259039 - }, - { - "type": "intermediary", - "timeSeconds": 1.000220404, - "uploadBytes": 0, - "downloadBytes": 79574472 - }, - { - "type": "intermediary", - "timeSeconds": 1.000006737, - "uploadBytes": 0, - "downloadBytes": 79825664 - }, - { - "type": "intermediary", - "timeSeconds": 1.000406386, - "uploadBytes": 0, - "downloadBytes": 79866112 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013876, - "uploadBytes": 0, - "downloadBytes": 80544896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000081637, - "uploadBytes": 0, - "downloadBytes": 80486656 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000403, - "uploadBytes": 0, - "downloadBytes": 42932216 - }, - { - "type": "intermediary", - "timeSeconds": 1.003687537, - "uploadBytes": 0, - "downloadBytes": 107038156 - }, - { - "type": "intermediary", - "timeSeconds": 1.000142124, - "uploadBytes": 0, - "downloadBytes": 107369148 - }, - { - "type": "intermediary", - "timeSeconds": 1.000173615, - "uploadBytes": 0, - "downloadBytes": 106890348 - }, - { - "type": "intermediary", - "timeSeconds": 1.000140625, - "uploadBytes": 0, - "downloadBytes": 106424816 - }, - { - "type": "intermediary", - "timeSeconds": 1.000104382, - "uploadBytes": 0, - "downloadBytes": 108327037 - }, - { - "type": "intermediary", - "timeSeconds": 1.000074936, - "uploadBytes": 0, - "downloadBytes": 107742331 - }, - { - "type": "intermediary", - "timeSeconds": 1.000043708, - "uploadBytes": 0, - "downloadBytes": 107407856 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018332, - "uploadBytes": 0, - "downloadBytes": 108121692 - }, - { - "type": "intermediary", - "timeSeconds": 1.000139265, - "uploadBytes": 0, - "downloadBytes": 108801056 - }, - { - "type": "intermediary", - "timeSeconds": 1.000045922, - "uploadBytes": 0, - "downloadBytes": 107865408 - }, - { - "type": "intermediary", - "timeSeconds": 1.000255429, - "uploadBytes": 0, - "downloadBytes": 108529024 - }, - { - "type": "intermediary", - "timeSeconds": 1.00010045, - "uploadBytes": 0, - "downloadBytes": 108932096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000307692, - "uploadBytes": 0, - "downloadBytes": 108241280 - }, - { - "type": "intermediary", - "timeSeconds": 1.000279191, - "uploadBytes": 0, - "downloadBytes": 109375360 - }, - { - "type": "intermediary", - "timeSeconds": 1.000028284, - "uploadBytes": 0, - "downloadBytes": 109379584 - }, - { - "type": "intermediary", - "timeSeconds": 1.000042287, - "uploadBytes": 0, - "downloadBytes": 109038720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000265677, - "uploadBytes": 0, - "downloadBytes": 109764096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000389881, - "uploadBytes": 0, - "downloadBytes": 110120177 - }, - { - "type": "intermediary", - "timeSeconds": 1.000646063, - "uploadBytes": 0, - "downloadBytes": 45262620 - }, - { - "type": "intermediary", - "timeSeconds": 1.000157702, - "uploadBytes": 0, - "downloadBytes": 75539996 - }, - { - "type": "intermediary", - "timeSeconds": 1.000062858, - "uploadBytes": 0, - "downloadBytes": 75688152 - }, - { - "type": "intermediary", - "timeSeconds": 1.000014673, - "uploadBytes": 0, - "downloadBytes": 75692668 - }, - { - "type": "intermediary", - "timeSeconds": 1.000144828, - "uploadBytes": 0, - "downloadBytes": 76213000 - }, - { - "type": "intermediary", - "timeSeconds": 1.000121138, - "uploadBytes": 0, - "downloadBytes": 76602233 - }, - { - "type": "intermediary", - "timeSeconds": 1.000209288, - "uploadBytes": 0, - "downloadBytes": 76900023 - }, - { - "type": "intermediary", - "timeSeconds": 1.000086277, - "uploadBytes": 0, - "downloadBytes": 77064408 - }, - { - "type": "intermediary", - "timeSeconds": 1.000193723, - "uploadBytes": 0, - "downloadBytes": 76926836 - }, - { - "type": "intermediary", - "timeSeconds": 1.000143561, - "uploadBytes": 0, - "downloadBytes": 77223705 - }, - { - "type": "intermediary", - "timeSeconds": 1.000049134, - "uploadBytes": 0, - "downloadBytes": 77744067 - }, - { - "type": "intermediary", - "timeSeconds": 1.000045171, - "uploadBytes": 0, - "downloadBytes": 77761580 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004377, - "uploadBytes": 0, - "downloadBytes": 78233320 - }, - { - "type": "intermediary", - "timeSeconds": 1.000062187, - "uploadBytes": 0, - "downloadBytes": 78098265 - }, - { - "type": "intermediary", - "timeSeconds": 1.00005189, - "uploadBytes": 0, - "downloadBytes": 78598680 - }, - { - "type": "intermediary", - "timeSeconds": 1.00011418, - "uploadBytes": 0, - "downloadBytes": 78620928 - }, - { - "type": "intermediary", - "timeSeconds": 1.000060024, - "uploadBytes": 0, - "downloadBytes": 78895503 - }, - { - "type": "intermediary", - "timeSeconds": 1.000162199, - "uploadBytes": 0, - "downloadBytes": 79204864 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000025, - "uploadBytes": 0, - "downloadBytes": 79234432 - }, - { - "type": "intermediary", - "timeSeconds": 1.000122196, - "uploadBytes": 0, - "downloadBytes": 51979855 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072027, - "uploadBytes": 0, - "downloadBytes": 109513277 - }, - { - "type": "intermediary", - "timeSeconds": 1.000035135, - "uploadBytes": 0, - "downloadBytes": 109755272 - }, - { - "type": "intermediary", - "timeSeconds": 1.000225367, - "uploadBytes": 0, - "downloadBytes": 109816009 - }, - { - "type": "intermediary", - "timeSeconds": 1.000091417, - "uploadBytes": 0, - "downloadBytes": 109760092 - }, - { - "type": "intermediary", - "timeSeconds": 1.000042034, - "uploadBytes": 0, - "downloadBytes": 109809512 - }, - { - "type": "intermediary", - "timeSeconds": 1.000091354, - "uploadBytes": 0, - "downloadBytes": 109996835 - }, - { - "type": "intermediary", - "timeSeconds": 1.00020437, - "uploadBytes": 0, - "downloadBytes": 110888044 - }, - { - "type": "intermediary", - "timeSeconds": 1.000145597, - "uploadBytes": 0, - "downloadBytes": 110821376 - }, - { - "type": "intermediary", - "timeSeconds": 1.000012014, - "uploadBytes": 0, - "downloadBytes": 110923889 - }, - { - "type": "intermediary", - "timeSeconds": 1.00001314, - "uploadBytes": 0, - "downloadBytes": 111389663 - }, - { - "type": "intermediary", - "timeSeconds": 1.000045917, - "uploadBytes": 0, - "downloadBytes": 111341440 - }, - { - "type": "intermediary", - "timeSeconds": 1.000181563, - "uploadBytes": 0, - "downloadBytes": 111405824 - }, - { - "type": "intermediary", - "timeSeconds": 1.000389625, - "uploadBytes": 0, - "downloadBytes": 112167040 - }, - { - "type": "intermediary", - "timeSeconds": 1.000063984, - "uploadBytes": 0, - "downloadBytes": 112139904 - }, - { - "type": "intermediary", - "timeSeconds": 1.000077796, - "uploadBytes": 0, - "downloadBytes": 112224384 - }, - { - "type": "intermediary", - "timeSeconds": 1.000296344, - "uploadBytes": 0, - "downloadBytes": 112173696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000245508, - "uploadBytes": 0, - "downloadBytes": 112741888 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019057, - "uploadBytes": 0, - "downloadBytes": 112890368 - }, - { - "type": "intermediary", - "timeSeconds": 1.010635234, - "uploadBytes": 0, - "downloadBytes": 56681158 - }, - { - "type": "intermediary", - "timeSeconds": 1.000091892, - "uploadBytes": 0, - "downloadBytes": 90733310 - }, - { - "type": "intermediary", - "timeSeconds": 1.000035505, - "uploadBytes": 0, - "downloadBytes": 77385308 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004129, - "uploadBytes": 0, - "downloadBytes": 77543208 - }, - { - "type": "intermediary", - "timeSeconds": 1.00018423, - "uploadBytes": 0, - "downloadBytes": 77545734 - }, - { - "type": "intermediary", - "timeSeconds": 1.000014864, - "uploadBytes": 0, - "downloadBytes": 77381370 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008225, - "uploadBytes": 0, - "downloadBytes": 78223969 - }, - { - "type": "intermediary", - "timeSeconds": 1.000016954, - "uploadBytes": 0, - "downloadBytes": 75195527 - }, - { - "type": "intermediary", - "timeSeconds": 1.000203934, - "uploadBytes": 0, - "downloadBytes": 55299676 - }, - { - "type": "intermediary", - "timeSeconds": 1.002870802, - "uploadBytes": 0, - "downloadBytes": 55058992 - }, - { - "type": "intermediary", - "timeSeconds": 1.000035903, - "uploadBytes": 0, - "downloadBytes": 55411808 - }, - { - "type": "intermediary", - "timeSeconds": 1.000154429, - "uploadBytes": 0, - "downloadBytes": 55906444 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018728, - "uploadBytes": 0, - "downloadBytes": 56197412 - }, - { - "type": "intermediary", - "timeSeconds": 1.000558168, - "uploadBytes": 0, - "downloadBytes": 56107288 - }, - { - "type": "intermediary", - "timeSeconds": 1.000015994, - "uploadBytes": 0, - "downloadBytes": 56454441 - }, - { - "type": "intermediary", - "timeSeconds": 1.00019756, - "uploadBytes": 0, - "downloadBytes": 56905895 - }, - { - "type": "intermediary", - "timeSeconds": 1.000081261, - "uploadBytes": 0, - "downloadBytes": 57161164 - }, - { - "type": "intermediary", - "timeSeconds": 1.000162385, - "uploadBytes": 0, - "downloadBytes": 57171584 - }, - { - "type": "intermediary", - "timeSeconds": 1.000147888, - "uploadBytes": 0, - "downloadBytes": 57375488 - }, - { - "type": "intermediary", - "timeSeconds": 1.000085255, - "uploadBytes": 0, - "downloadBytes": 42501828 - }, - { - "type": "intermediary", - "timeSeconds": 1.00048423, - "uploadBytes": 0, - "downloadBytes": 106171944 - }, - { - "type": "intermediary", - "timeSeconds": 1.000501719, - "uploadBytes": 0, - "downloadBytes": 107259829 - }, - { - "type": "intermediary", - "timeSeconds": 1.000201453, - "uploadBytes": 0, - "downloadBytes": 107129327 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002561, - "uploadBytes": 0, - "downloadBytes": 106875361 - }, - { - "type": "intermediary", - "timeSeconds": 1.000231192, - "uploadBytes": 0, - "downloadBytes": 106929071 - }, - { - "type": "intermediary", - "timeSeconds": 1.000066192, - "uploadBytes": 0, - "downloadBytes": 108379880 - }, - { - "type": "intermediary", - "timeSeconds": 1.00020607, - "uploadBytes": 0, - "downloadBytes": 107543712 - }, - { - "type": "intermediary", - "timeSeconds": 1.000097911, - "uploadBytes": 0, - "downloadBytes": 107721696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000039801, - "uploadBytes": 0, - "downloadBytes": 108739476 - }, - { - "type": "intermediary", - "timeSeconds": 1.000028576, - "uploadBytes": 0, - "downloadBytes": 108350180 - }, - { - "type": "intermediary", - "timeSeconds": 1.00023866, - "uploadBytes": 0, - "downloadBytes": 108466048 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011079, - "uploadBytes": 0, - "downloadBytes": 108244608 - }, - { - "type": "intermediary", - "timeSeconds": 1.000282335, - "uploadBytes": 0, - "downloadBytes": 109471872 - }, - { - "type": "intermediary", - "timeSeconds": 1.000264675, - "uploadBytes": 0, - "downloadBytes": 109111552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000023488, - "uploadBytes": 0, - "downloadBytes": 108849664 - }, - { - "type": "intermediary", - "timeSeconds": 1.000015189, - "uploadBytes": 0, - "downloadBytes": 109987712 - }, - { - "type": "intermediary", - "timeSeconds": 1.000198632, - "uploadBytes": 0, - "downloadBytes": 110092032 - }, - { - "type": "intermediary", - "timeSeconds": 1.000051954, - "uploadBytes": 0, - "downloadBytes": 110009856 - }, - { - "type": "intermediary", - "timeSeconds": 1.000039822, - "uploadBytes": 0, - "downloadBytes": 42835028 - }, - { - "type": "intermediary", - "timeSeconds": 1.000092075, - "uploadBytes": 0, - "downloadBytes": 105060493 - }, - { - "type": "intermediary", - "timeSeconds": 1.000174577, - "uploadBytes": 0, - "downloadBytes": 105483599 - }, - { - "type": "intermediary", - "timeSeconds": 1.000104449, - "uploadBytes": 0, - "downloadBytes": 106623953 - }, - { - "type": "intermediary", - "timeSeconds": 1.000132309, - "uploadBytes": 0, - "downloadBytes": 105554203 - }, - { - "type": "intermediary", - "timeSeconds": 1.000105942, - "uploadBytes": 0, - "downloadBytes": 107376777 - }, - { - "type": "intermediary", - "timeSeconds": 1.000174403, - "uploadBytes": 0, - "downloadBytes": 105903087 - }, - { - "type": "intermediary", - "timeSeconds": 1.000078449, - "uploadBytes": 0, - "downloadBytes": 107397388 - }, - { - "type": "intermediary", - "timeSeconds": 1.000101838, - "uploadBytes": 0, - "downloadBytes": 106955616 - }, - { - "type": "intermediary", - "timeSeconds": 1.000122761, - "uploadBytes": 0, - "downloadBytes": 107271964 - }, - { - "type": "intermediary", - "timeSeconds": 1.00020142, - "uploadBytes": 0, - "downloadBytes": 107195620 - }, - { - "type": "intermediary", - "timeSeconds": 1.000190622, - "uploadBytes": 0, - "downloadBytes": 107269760 - }, - { - "type": "intermediary", - "timeSeconds": 1.000145038, - "uploadBytes": 0, - "downloadBytes": 107679872 - }, - { - "type": "intermediary", - "timeSeconds": 1.000253842, - "uploadBytes": 0, - "downloadBytes": 107253248 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020077, - "uploadBytes": 0, - "downloadBytes": 108707584 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018565, - "uploadBytes": 0, - "downloadBytes": 107568256 - }, - { - "type": "intermediary", - "timeSeconds": 1.000328803, - "uploadBytes": 0, - "downloadBytes": 109012736 - }, - { - "type": "intermediary", - "timeSeconds": 1.000050249, - "uploadBytes": 0, - "downloadBytes": 108178560 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031605, - "uploadBytes": 0, - "downloadBytes": 109114880 - }, - { - "type": "intermediary", - "timeSeconds": 1.017051379, - "uploadBytes": 0, - "downloadBytes": 49646632 - }, - { - "type": "intermediary", - "timeSeconds": 1.00002019, - "uploadBytes": 0, - "downloadBytes": 81588905 - }, - { - "type": "intermediary", - "timeSeconds": 1.000040181, - "uploadBytes": 0, - "downloadBytes": 76540411 - }, - { - "type": "intermediary", - "timeSeconds": 1.000105496, - "uploadBytes": 0, - "downloadBytes": 76380224 - }, - { - "type": "intermediary", - "timeSeconds": 1.000223694, - "uploadBytes": 0, - "downloadBytes": 76852548 - }, - { - "type": "intermediary", - "timeSeconds": 1.00009545, - "uploadBytes": 0, - "downloadBytes": 77012125 - }, - { - "type": "intermediary", - "timeSeconds": 1.000189938, - "uploadBytes": 0, - "downloadBytes": 77326552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000048663, - "uploadBytes": 0, - "downloadBytes": 77561031 - }, - { - "type": "intermediary", - "timeSeconds": 1.000253904, - "uploadBytes": 0, - "downloadBytes": 77890376 - }, - { - "type": "intermediary", - "timeSeconds": 1.000281694, - "uploadBytes": 0, - "downloadBytes": 78134724 - }, - { - "type": "intermediary", - "timeSeconds": 1.000219943, - "uploadBytes": 0, - "downloadBytes": 78371172 - }, - { - "type": "intermediary", - "timeSeconds": 1.000286685, - "uploadBytes": 0, - "downloadBytes": 78599961 - }, - { - "type": "intermediary", - "timeSeconds": 1.000270081, - "uploadBytes": 0, - "downloadBytes": 78899696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000294295, - "uploadBytes": 0, - "downloadBytes": 79160723 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031506, - "uploadBytes": 0, - "downloadBytes": 79122024 - }, - { - "type": "intermediary", - "timeSeconds": 1.00001901, - "uploadBytes": 0, - "downloadBytes": 79410560 - }, - { - "type": "intermediary", - "timeSeconds": 1.000043079, - "uploadBytes": 0, - "downloadBytes": 79515889 - }, - { - "type": "intermediary", - "timeSeconds": 1.000198125, - "uploadBytes": 0, - "downloadBytes": 79786880 - }, - { - "type": "intermediary", - "timeSeconds": 1.00008841, - "uploadBytes": 0, - "downloadBytes": 80139264 - }, - { - "type": "intermediary", - "timeSeconds": 1.000176567, - "uploadBytes": 0, - "downloadBytes": 46988636 - }, - { - "type": "intermediary", - "timeSeconds": 1.000323122, - "uploadBytes": 0, - "downloadBytes": 75252668 - }, - { - "type": "intermediary", - "timeSeconds": 1.000251135, - "uploadBytes": 0, - "downloadBytes": 76005096 - }, - { - "type": "intermediary", - "timeSeconds": 1.001211508, - "uploadBytes": 0, - "downloadBytes": 76229664 - }, - { - "type": "intermediary", - "timeSeconds": 1.000068236, - "uploadBytes": 0, - "downloadBytes": 76111300 - }, - { - "type": "intermediary", - "timeSeconds": 1.000127221, - "uploadBytes": 0, - "downloadBytes": 75992656 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000303, - "uploadBytes": 0, - "downloadBytes": 76359628 - }, - { - "type": "intermediary", - "timeSeconds": 1.000046508, - "uploadBytes": 0, - "downloadBytes": 76499148 - }, - { - "type": "intermediary", - "timeSeconds": 1.000078311, - "uploadBytes": 0, - "downloadBytes": 76697153 - }, - { - "type": "intermediary", - "timeSeconds": 1.000132009, - "uploadBytes": 0, - "downloadBytes": 77071748 - }, - { - "type": "intermediary", - "timeSeconds": 1.000256997, - "uploadBytes": 0, - "downloadBytes": 77546351 - }, - { - "type": "intermediary", - "timeSeconds": 1.000087442, - "uploadBytes": 0, - "downloadBytes": 77829356 - }, - { - "type": "intermediary", - "timeSeconds": 1.000060385, - "uploadBytes": 0, - "downloadBytes": 78082480 - }, - { - "type": "intermediary", - "timeSeconds": 1.000038593, - "uploadBytes": 0, - "downloadBytes": 78121456 - }, - { - "type": "intermediary", - "timeSeconds": 1.000090718, - "uploadBytes": 0, - "downloadBytes": 77932133 - }, - { - "type": "intermediary", - "timeSeconds": 1.000092114, - "uploadBytes": 0, - "downloadBytes": 78265728 - }, - { - "type": "intermediary", - "timeSeconds": 1.000288797, - "uploadBytes": 0, - "downloadBytes": 78566415 - }, - { - "type": "intermediary", - "timeSeconds": 1.000082995, - "uploadBytes": 0, - "downloadBytes": 78813056 - }, - { - "type": "intermediary", - "timeSeconds": 1.000098095, - "uploadBytes": 0, - "downloadBytes": 79101952 - } - ], - "implementation": "go-libp2p", - "version": "v0.41", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.006549233, - "uploadBytes": 0, - "downloadBytes": 25165824 - }, - { - "type": "intermediary", - "timeSeconds": 1.053427597, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.049747965, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.05174976, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.050450624, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.053785741, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.053181563, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.053633627, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054471796, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054616627, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.053053335, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.052600751, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.051007555, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.050999688, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.052849341, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.051987426, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.051407041, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.050279642, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.011456511, - "uploadBytes": 0, - "downloadBytes": 25165824 - }, - { - "type": "intermediary", - "timeSeconds": 1.061402036, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.061282984, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.060487632, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055116062, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.05944653, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058595086, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058753416, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059108611, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.057214492, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059253693, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.061198046, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.059570364, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.056043538, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.056621489, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.06164545, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055996868, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.056366314, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.005945672, - "uploadBytes": 0, - "downloadBytes": 25165824 - }, - { - "type": "intermediary", - "timeSeconds": 1.000213566, - "uploadBytes": 0, - "downloadBytes": 96804864 - }, - { - "type": "intermediary", - "timeSeconds": 1.048790812, - "uploadBytes": 0, - "downloadBytes": 68354048 - }, - { - "type": "intermediary", - "timeSeconds": 1.022294363, - "uploadBytes": 0, - "downloadBytes": 55902208 - }, - { - "type": "intermediary", - "timeSeconds": 1.000087266, - "uploadBytes": 0, - "downloadBytes": 46530560 - }, - { - "type": "intermediary", - "timeSeconds": 1.000168692, - "uploadBytes": 0, - "downloadBytes": 43122688 - }, - { - "type": "intermediary", - "timeSeconds": 1.000136541, - "uploadBytes": 0, - "downloadBytes": 45481984 - }, - { - "type": "intermediary", - "timeSeconds": 1.057248086, - "uploadBytes": 0, - "downloadBytes": 46456832 - }, - { - "type": "intermediary", - "timeSeconds": 1.050771314, - "uploadBytes": 0, - "downloadBytes": 40837120 - }, - { - "type": "intermediary", - "timeSeconds": 1.045131033, - "uploadBytes": 0, - "downloadBytes": 34660352 - }, - { - "type": "intermediary", - "timeSeconds": 1.041823632, - "uploadBytes": 0, - "downloadBytes": 36184064 - }, - { - "type": "intermediary", - "timeSeconds": 1.043359707, - "uploadBytes": 0, - "downloadBytes": 30924800 - }, - { - "type": "intermediary", - "timeSeconds": 1.044742808, - "uploadBytes": 0, - "downloadBytes": 26615808 - }, - { - "type": "intermediary", - "timeSeconds": 1.040823317, - "uploadBytes": 0, - "downloadBytes": 23715840 - }, - { - "type": "intermediary", - "timeSeconds": 1.037959392, - "uploadBytes": 0, - "downloadBytes": 24649728 - }, - { - "type": "intermediary", - "timeSeconds": 1.036895675, - "uploadBytes": 0, - "downloadBytes": 23789568 - }, - { - "type": "intermediary", - "timeSeconds": 1.039705991, - "uploadBytes": 0, - "downloadBytes": 25231360 - }, - { - "type": "intermediary", - "timeSeconds": 1.043446073, - "uploadBytes": 0, - "downloadBytes": 26992640 - }, - { - "type": "intermediary", - "timeSeconds": 1.046800287, - "uploadBytes": 0, - "downloadBytes": 28516352 - }, - { - "type": "intermediary", - "timeSeconds": 1.009774381, - "uploadBytes": 0, - "downloadBytes": 16777216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027057, - "uploadBytes": 0, - "downloadBytes": 113385472 - }, - { - "type": "intermediary", - "timeSeconds": 1.061894491, - "uploadBytes": 0, - "downloadBytes": 113106944 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011116, - "uploadBytes": 0, - "downloadBytes": 113451008 - }, - { - "type": "intermediary", - "timeSeconds": 1.061915544, - "uploadBytes": 0, - "downloadBytes": 113041408 - }, - { - "type": "intermediary", - "timeSeconds": 1.000095017, - "uploadBytes": 0, - "downloadBytes": 115679232 - }, - { - "type": "intermediary", - "timeSeconds": 1.053009657, - "uploadBytes": 0, - "downloadBytes": 110813184 - }, - { - "type": "intermediary", - "timeSeconds": 1.000079455, - "uploadBytes": 0, - "downloadBytes": 115613696 - }, - { - "type": "intermediary", - "timeSeconds": 1.056348092, - "uploadBytes": 0, - "downloadBytes": 110878720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000031187, - "uploadBytes": 0, - "downloadBytes": 114958336 - }, - { - "type": "intermediary", - "timeSeconds": 1.058922009, - "uploadBytes": 0, - "downloadBytes": 111534080 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000402, - "uploadBytes": 0, - "downloadBytes": 113418240 - }, - { - "type": "intermediary", - "timeSeconds": 1.062081233, - "uploadBytes": 0, - "downloadBytes": 113074176 - }, - { - "type": "intermediary", - "timeSeconds": 1.000106182, - "uploadBytes": 0, - "downloadBytes": 114302976 - }, - { - "type": "intermediary", - "timeSeconds": 1.055654057, - "uploadBytes": 0, - "downloadBytes": 112189440 - }, - { - "type": "intermediary", - "timeSeconds": 1.000055018, - "uploadBytes": 0, - "downloadBytes": 116203520 - }, - { - "type": "intermediary", - "timeSeconds": 1.054419317, - "uploadBytes": 0, - "downloadBytes": 110288896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000095927, - "uploadBytes": 0, - "downloadBytes": 115220480 - }, - { - "type": "intermediary", - "timeSeconds": 1.042128818, - "uploadBytes": 0, - "downloadBytes": 102883328 - }, - { - "type": "intermediary", - "timeSeconds": 1.011591551, - "uploadBytes": 0, - "downloadBytes": 33685504 - }, - { - "type": "intermediary", - "timeSeconds": 1.003618558, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.005768553, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.003526959, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004801016, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.002953661, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004006557, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004692314, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.005430733, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.002372113, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.00351594, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.003869196, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.003481633, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004286993, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004667571, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.002334329, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.006630956, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.004680913, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.0067357, - "uploadBytes": 0, - "downloadBytes": 109051904 - }, - { - "type": "intermediary", - "timeSeconds": 1.013142551, - "uploadBytes": 0, - "downloadBytes": 16777216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000203123, - "uploadBytes": 0, - "downloadBytes": 113451008 - }, - { - "type": "intermediary", - "timeSeconds": 1.05846307, - "uploadBytes": 0, - "downloadBytes": 113041408 - }, - { - "type": "intermediary", - "timeSeconds": 1.000046826, - "uploadBytes": 0, - "downloadBytes": 116137984 - }, - { - "type": "intermediary", - "timeSeconds": 1.055679752, - "uploadBytes": 0, - "downloadBytes": 110354432 - }, - { - "type": "intermediary", - "timeSeconds": 1.00010608, - "uploadBytes": 0, - "downloadBytes": 115482624 - }, - { - "type": "intermediary", - "timeSeconds": 1.057042421, - "uploadBytes": 0, - "downloadBytes": 111009792 - }, - { - "type": "intermediary", - "timeSeconds": 1.000055278, - "uploadBytes": 0, - "downloadBytes": 114565120 - }, - { - "type": "intermediary", - "timeSeconds": 1.059501094, - "uploadBytes": 0, - "downloadBytes": 111927296 - }, - { - "type": "intermediary", - "timeSeconds": 1.000085318, - "uploadBytes": 0, - "downloadBytes": 114827264 - }, - { - "type": "intermediary", - "timeSeconds": 1.056955624, - "uploadBytes": 0, - "downloadBytes": 111665152 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018767, - "uploadBytes": 0, - "downloadBytes": 114958336 - }, - { - "type": "intermediary", - "timeSeconds": 1.056537024, - "uploadBytes": 0, - "downloadBytes": 111534080 - }, - { - "type": "intermediary", - "timeSeconds": 1.000070231, - "uploadBytes": 0, - "downloadBytes": 115875840 - }, - { - "type": "intermediary", - "timeSeconds": 1.054830033, - "uploadBytes": 0, - "downloadBytes": 110616576 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000004, - "uploadBytes": 0, - "downloadBytes": 114556928 - }, - { - "type": "intermediary", - "timeSeconds": 1.055944007, - "uploadBytes": 0, - "downloadBytes": 111935488 - }, - { - "type": "intermediary", - "timeSeconds": 1.000119475, - "uploadBytes": 0, - "downloadBytes": 114499584 - }, - { - "type": "intermediary", - "timeSeconds": 1.056556293, - "uploadBytes": 0, - "downloadBytes": 111992832 - }, - { - "type": "intermediary", - "timeSeconds": 1.013455772, - "uploadBytes": 0, - "downloadBytes": 16908288 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020901, - "uploadBytes": 0, - "downloadBytes": 114302976 - }, - { - "type": "intermediary", - "timeSeconds": 1.056096326, - "uploadBytes": 0, - "downloadBytes": 112189440 - }, - { - "type": "intermediary", - "timeSeconds": 1.000022083, - "uploadBytes": 0, - "downloadBytes": 114106368 - }, - { - "type": "intermediary", - "timeSeconds": 1.060088239, - "uploadBytes": 0, - "downloadBytes": 112386048 - }, - { - "type": "intermediary", - "timeSeconds": 1.000105696, - "uploadBytes": 0, - "downloadBytes": 113582080 - }, - { - "type": "intermediary", - "timeSeconds": 1.061016476, - "uploadBytes": 0, - "downloadBytes": 112910336 - }, - { - "type": "intermediary", - "timeSeconds": 1.000088512, - "uploadBytes": 0, - "downloadBytes": 116072448 - }, - { - "type": "intermediary", - "timeSeconds": 1.057388278, - "uploadBytes": 0, - "downloadBytes": 110419968 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002141, - "uploadBytes": 0, - "downloadBytes": 113647616 - }, - { - "type": "intermediary", - "timeSeconds": 1.059850577, - "uploadBytes": 0, - "downloadBytes": 112844800 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000179, - "uploadBytes": 0, - "downloadBytes": 116236288 - }, - { - "type": "intermediary", - "timeSeconds": 1.054578968, - "uploadBytes": 0, - "downloadBytes": 110256128 - }, - { - "type": "intermediary", - "timeSeconds": 1.000049433, - "uploadBytes": 0, - "downloadBytes": 111550464 - }, - { - "type": "intermediary", - "timeSeconds": 1.000039586, - "uploadBytes": 0, - "downloadBytes": 113639424 - }, - { - "type": "intermediary", - "timeSeconds": 1.056082138, - "uploadBytes": 0, - "downloadBytes": 110354432 - }, - { - "type": "intermediary", - "timeSeconds": 1.000067791, - "uploadBytes": 0, - "downloadBytes": 114630656 - }, - { - "type": "intermediary", - "timeSeconds": 1.059365254, - "uploadBytes": 0, - "downloadBytes": 111861760 - }, - { - "type": "intermediary", - "timeSeconds": 1.000026554, - "uploadBytes": 0, - "downloadBytes": 115154944 - }, - { - "type": "intermediary", - "timeSeconds": 1.042470239, - "uploadBytes": 0, - "downloadBytes": 33554432 - }, - { - "type": "intermediary", - "timeSeconds": 1.00009572, - "uploadBytes": 0, - "downloadBytes": 116465664 - }, - { - "type": "intermediary", - "timeSeconds": 1.058617411, - "uploadBytes": 0, - "downloadBytes": 110026752 - }, - { - "type": "intermediary", - "timeSeconds": 1.000079361, - "uploadBytes": 0, - "downloadBytes": 115023872 - }, - { - "type": "intermediary", - "timeSeconds": 1.060784485, - "uploadBytes": 0, - "downloadBytes": 111468544 - }, - { - "type": "intermediary", - "timeSeconds": 1.000018099, - "uploadBytes": 0, - "downloadBytes": 115286016 - }, - { - "type": "intermediary", - "timeSeconds": 1.053123035, - "uploadBytes": 0, - "downloadBytes": 111206400 - }, - { - "type": "intermediary", - "timeSeconds": 1.000030503, - "uploadBytes": 0, - "downloadBytes": 113057792 - }, - { - "type": "intermediary", - "timeSeconds": 1.062242986, - "uploadBytes": 0, - "downloadBytes": 113434624 - }, - { - "type": "intermediary", - "timeSeconds": 1.000067538, - "uploadBytes": 0, - "downloadBytes": 113385472 - }, - { - "type": "intermediary", - "timeSeconds": 1.000016959, - "uploadBytes": 0, - "downloadBytes": 112197632 - }, - { - "type": "intermediary", - "timeSeconds": 1.051453604, - "uploadBytes": 0, - "downloadBytes": 109961216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000056728, - "uploadBytes": 0, - "downloadBytes": 112926720 - }, - { - "type": "intermediary", - "timeSeconds": 1.059188481, - "uploadBytes": 0, - "downloadBytes": 113565696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017493, - "uploadBytes": 0, - "downloadBytes": 116531200 - }, - { - "type": "intermediary", - "timeSeconds": 1.053832681, - "uploadBytes": 0, - "downloadBytes": 109961216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004783, - "uploadBytes": 0, - "downloadBytes": 115023872 - }, - { - "type": "intermediary", - "timeSeconds": 1.056045135, - "uploadBytes": 0, - "downloadBytes": 111468544 - }, - { - "type": "intermediary", - "timeSeconds": 1.000101699, - "uploadBytes": 0, - "downloadBytes": 113123328 - }, - { - "type": "intermediary", - "timeSeconds": 1.036525197, - "uploadBytes": 0, - "downloadBytes": 33554432 - }, - { - "type": "intermediary", - "timeSeconds": 1.001639073, - "uploadBytes": 0, - "downloadBytes": 92274688 - }, - { - "type": "intermediary", - "timeSeconds": 1.05151884, - "uploadBytes": 0, - "downloadBytes": 67108864 - }, - { - "type": "intermediary", - "timeSeconds": 1.026562179, - "uploadBytes": 0, - "downloadBytes": 40181760 - }, - { - "type": "intermediary", - "timeSeconds": 1.023540152, - "uploadBytes": 0, - "downloadBytes": 28508160 - }, - { - "type": "intermediary", - "timeSeconds": 1.019078024, - "uploadBytes": 0, - "downloadBytes": 27000832 - }, - { - "type": "intermediary", - "timeSeconds": 1.017414534, - "uploadBytes": 0, - "downloadBytes": 27131904 - }, - { - "type": "intermediary", - "timeSeconds": 1.014563934, - "uploadBytes": 0, - "downloadBytes": 27131904 - }, - { - "type": "intermediary", - "timeSeconds": 1.016814104, - "uploadBytes": 0, - "downloadBytes": 26206208 - }, - { - "type": "intermediary", - "timeSeconds": 1.015439488, - "uploadBytes": 0, - "downloadBytes": 27074560 - }, - { - "type": "intermediary", - "timeSeconds": 1.01238957, - "uploadBytes": 0, - "downloadBytes": 27066368 - }, - { - "type": "intermediary", - "timeSeconds": 1.012374459, - "uploadBytes": 0, - "downloadBytes": 27131904 - }, - { - "type": "intermediary", - "timeSeconds": 1.012523614, - "uploadBytes": 0, - "downloadBytes": 27066368 - }, - { - "type": "intermediary", - "timeSeconds": 1.015682787, - "uploadBytes": 0, - "downloadBytes": 25878528 - }, - { - "type": "intermediary", - "timeSeconds": 1.013881306, - "uploadBytes": 0, - "downloadBytes": 27074560 - }, - { - "type": "intermediary", - "timeSeconds": 1.013407891, - "uploadBytes": 0, - "downloadBytes": 27131904 - }, - { - "type": "intermediary", - "timeSeconds": 1.014444233, - "uploadBytes": 0, - "downloadBytes": 27131904 - }, - { - "type": "intermediary", - "timeSeconds": 1.013598541, - "uploadBytes": 0, - "downloadBytes": 27197440 - }, - { - "type": "intermediary", - "timeSeconds": 1.022197164, - "uploadBytes": 0, - "downloadBytes": 22740992 - }, - { - "type": "intermediary", - "timeSeconds": 1.000064698, - "uploadBytes": 0, - "downloadBytes": 9838592 - }, - { - "type": "intermediary", - "timeSeconds": 1.026223648, - "uploadBytes": 0, - "downloadBytes": 107601920 - }, - { - "type": "intermediary", - "timeSeconds": 1.055270181, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054330847, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.056810114, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055867022, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058484151, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054776039, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.058303866, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055543018, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055265459, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.057073778, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.055429172, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.057222506, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.054908269, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.05837889, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.057732236, - "uploadBytes": 0, - "downloadBytes": 117440512 - }, - { - "type": "intermediary", - "timeSeconds": 1.053442179, - "uploadBytes": 0, - "downloadBytes": 117440512 - } - ], - "implementation": "go-libp2p", - "version": "v0.42", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.000262556, - "uploadBytes": 0, - "downloadBytes": 48111616 - }, - { - "type": "intermediary", - "timeSeconds": 1.000014448, - "uploadBytes": 0, - "downloadBytes": 106368032 - }, - { - "type": "intermediary", - "timeSeconds": 1.000083056, - "uploadBytes": 0, - "downloadBytes": 106363516 - }, - { - "type": "intermediary", - "timeSeconds": 1.00004143, - "uploadBytes": 0, - "downloadBytes": 108044261 - }, - { - "type": "intermediary", - "timeSeconds": 1.000238239, - "uploadBytes": 0, - "downloadBytes": 106903935 - }, - { - "type": "intermediary", - "timeSeconds": 1.00010768, - "uploadBytes": 0, - "downloadBytes": 107028480 - }, - { - "type": "intermediary", - "timeSeconds": 1.000135798, - "uploadBytes": 0, - "downloadBytes": 107694004 - }, - { - "type": "intermediary", - "timeSeconds": 1.000017809, - "uploadBytes": 0, - "downloadBytes": 108167156 - }, - { - "type": "intermediary", - "timeSeconds": 1.000033314, - "uploadBytes": 0, - "downloadBytes": 108080744 - }, - { - "type": "intermediary", - "timeSeconds": 1.000057673, - "uploadBytes": 0, - "downloadBytes": 107950500 - }, - { - "type": "intermediary", - "timeSeconds": 1.000113798, - "uploadBytes": 0, - "downloadBytes": 108847948 - }, - { - "type": "intermediary", - "timeSeconds": 1.000108365, - "uploadBytes": 0, - "downloadBytes": 108621568 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000064, - "uploadBytes": 0, - "downloadBytes": 108483200 - }, - { - "type": "intermediary", - "timeSeconds": 1.000258856, - "uploadBytes": 0, - "downloadBytes": 108624896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000075139, - "uploadBytes": 0, - "downloadBytes": 109604096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000089689, - "uploadBytes": 0, - "downloadBytes": 109244288 - }, - { - "type": "intermediary", - "timeSeconds": 1.000052706, - "uploadBytes": 0, - "downloadBytes": 109414400 - }, - { - "type": "intermediary", - "timeSeconds": 1.000095418, - "uploadBytes": 0, - "downloadBytes": 110112896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000066607, - "uploadBytes": 0, - "downloadBytes": 110301312 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010746, - "uploadBytes": 0, - "downloadBytes": 47023578 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009721, - "uploadBytes": 0, - "downloadBytes": 110658862 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013848, - "uploadBytes": 0, - "downloadBytes": 110518832 - }, - { - "type": "intermediary", - "timeSeconds": 1.000038708, - "uploadBytes": 0, - "downloadBytes": 110149072 - }, - { - "type": "intermediary", - "timeSeconds": 1.000183622, - "uploadBytes": 0, - "downloadBytes": 110101877 - }, - { - "type": "intermediary", - "timeSeconds": 1.00041907, - "uploadBytes": 0, - "downloadBytes": 111421099 - }, - { - "type": "intermediary", - "timeSeconds": 1.000014576, - "uploadBytes": 0, - "downloadBytes": 111513448 - }, - { - "type": "intermediary", - "timeSeconds": 1.000192862, - "uploadBytes": 0, - "downloadBytes": 111441716 - }, - { - "type": "intermediary", - "timeSeconds": 1.000006181, - "uploadBytes": 0, - "downloadBytes": 110916564 - }, - { - "type": "intermediary", - "timeSeconds": 1.000065454, - "uploadBytes": 0, - "downloadBytes": 111526445 - }, - { - "type": "intermediary", - "timeSeconds": 1.000145274, - "uploadBytes": 0, - "downloadBytes": 111804347 - }, - { - "type": "intermediary", - "timeSeconds": 1.000181585, - "uploadBytes": 0, - "downloadBytes": 112079488 - }, - { - "type": "intermediary", - "timeSeconds": 1.000044512, - "uploadBytes": 0, - "downloadBytes": 112144768 - }, - { - "type": "intermediary", - "timeSeconds": 1.000179979, - "uploadBytes": 0, - "downloadBytes": 111888768 - }, - { - "type": "intermediary", - "timeSeconds": 1.000109879, - "uploadBytes": 0, - "downloadBytes": 112193664 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000528, - "uploadBytes": 0, - "downloadBytes": 112637312 - }, - { - "type": "intermediary", - "timeSeconds": 1.000099949, - "uploadBytes": 0, - "downloadBytes": 113386880 - }, - { - "type": "intermediary", - "timeSeconds": 1.000008436, - "uploadBytes": 0, - "downloadBytes": 113111936 - }, - { - "type": "intermediary", - "timeSeconds": 1.000021198, - "uploadBytes": 0, - "downloadBytes": 112921728 - }, - { - "type": "intermediary", - "timeSeconds": 1.000250044, - "uploadBytes": 0, - "downloadBytes": 41633212 - }, - { - "type": "intermediary", - "timeSeconds": 1.000061045, - "uploadBytes": 0, - "downloadBytes": 106740292 - }, - { - "type": "intermediary", - "timeSeconds": 1.000163913, - "uploadBytes": 0, - "downloadBytes": 104874264 - }, - { - "type": "intermediary", - "timeSeconds": 1.00002552, - "uploadBytes": 0, - "downloadBytes": 106631588 - }, - { - "type": "intermediary", - "timeSeconds": 1.000029252, - "uploadBytes": 0, - "downloadBytes": 105509856 - }, - { - "type": "intermediary", - "timeSeconds": 1.000159701, - "uploadBytes": 0, - "downloadBytes": 106725084 - }, - { - "type": "intermediary", - "timeSeconds": 1.000034522, - "uploadBytes": 0, - "downloadBytes": 106579892 - }, - { - "type": "intermediary", - "timeSeconds": 1.000209964, - "uploadBytes": 0, - "downloadBytes": 106346852 - }, - { - "type": "intermediary", - "timeSeconds": 1.000044598, - "uploadBytes": 0, - "downloadBytes": 107299096 - }, - { - "type": "intermediary", - "timeSeconds": 1.00003093, - "uploadBytes": 0, - "downloadBytes": 106973972 - }, - { - "type": "intermediary", - "timeSeconds": 1.000012287, - "uploadBytes": 0, - "downloadBytes": 107844405 - }, - { - "type": "intermediary", - "timeSeconds": 1.000129286, - "uploadBytes": 0, - "downloadBytes": 106937871 - }, - { - "type": "intermediary", - "timeSeconds": 1.000262776, - "uploadBytes": 0, - "downloadBytes": 108254464 - }, - { - "type": "intermediary", - "timeSeconds": 1.000203927, - "uploadBytes": 0, - "downloadBytes": 107044224 - }, - { - "type": "intermediary", - "timeSeconds": 1.000070853, - "uploadBytes": 0, - "downloadBytes": 108480896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000235702, - "uploadBytes": 0, - "downloadBytes": 107470848 - }, - { - "type": "intermediary", - "timeSeconds": 1.000255718, - "uploadBytes": 0, - "downloadBytes": 109022976 - }, - { - "type": "intermediary", - "timeSeconds": 1.000203571, - "uploadBytes": 0, - "downloadBytes": 108719744 - }, - { - "type": "intermediary", - "timeSeconds": 1.000052429, - "uploadBytes": 0, - "downloadBytes": 108945024 - }, - { - "type": "intermediary", - "timeSeconds": 1.000255436, - "uploadBytes": 0, - "downloadBytes": 53187523 - }, - { - "type": "intermediary", - "timeSeconds": 1.00028087, - "uploadBytes": 0, - "downloadBytes": 108307021 - }, - { - "type": "intermediary", - "timeSeconds": 1.000009248, - "uploadBytes": 0, - "downloadBytes": 108329596 - }, - { - "type": "intermediary", - "timeSeconds": 1.000015458, - "uploadBytes": 0, - "downloadBytes": 108584960 - }, - { - "type": "intermediary", - "timeSeconds": 1.000058415, - "uploadBytes": 0, - "downloadBytes": 108791720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000041651, - "uploadBytes": 0, - "downloadBytes": 108942596 - }, - { - "type": "intermediary", - "timeSeconds": 1.000011203, - "uploadBytes": 0, - "downloadBytes": 107973372 - }, - { - "type": "intermediary", - "timeSeconds": 1.000189746, - "uploadBytes": 0, - "downloadBytes": 109316044 - }, - { - "type": "intermediary", - "timeSeconds": 1.000085696, - "uploadBytes": 0, - "downloadBytes": 109752168 - }, - { - "type": "intermediary", - "timeSeconds": 1.000078205, - "uploadBytes": 0, - "downloadBytes": 110114880 - }, - { - "type": "intermediary", - "timeSeconds": 1.000237627, - "uploadBytes": 0, - "downloadBytes": 109975640 - }, - { - "type": "intermediary", - "timeSeconds": 1.000157353, - "uploadBytes": 0, - "downloadBytes": 110139648 - }, - { - "type": "intermediary", - "timeSeconds": 1.000010227, - "uploadBytes": 0, - "downloadBytes": 110407040 - }, - { - "type": "intermediary", - "timeSeconds": 1.000157228, - "uploadBytes": 0, - "downloadBytes": 110700160 - }, - { - "type": "intermediary", - "timeSeconds": 1.000143546, - "uploadBytes": 0, - "downloadBytes": 110895360 - }, - { - "type": "intermediary", - "timeSeconds": 1.000069515, - "uploadBytes": 0, - "downloadBytes": 111090816 - }, - { - "type": "intermediary", - "timeSeconds": 1.000156598, - "uploadBytes": 0, - "downloadBytes": 111367552 - }, - { - "type": "intermediary", - "timeSeconds": 1.000001748, - "uploadBytes": 0, - "downloadBytes": 111370240 - }, - { - "type": "intermediary", - "timeSeconds": 1.000120685, - "uploadBytes": 0, - "downloadBytes": 111735168 - }, - { - "type": "intermediary", - "timeSeconds": 1.000054726, - "uploadBytes": 0, - "downloadBytes": 45294948 - }, - { - "type": "intermediary", - "timeSeconds": 1.000059845, - "uploadBytes": 0, - "downloadBytes": 107395997 - }, - { - "type": "intermediary", - "timeSeconds": 1.000309409, - "uploadBytes": 0, - "downloadBytes": 107463519 - }, - { - "type": "intermediary", - "timeSeconds": 1.000100933, - "uploadBytes": 0, - "downloadBytes": 107897124 - }, - { - "type": "intermediary", - "timeSeconds": 1.000000279, - "uploadBytes": 0, - "downloadBytes": 108155580 - }, - { - "type": "intermediary", - "timeSeconds": 1.000044595, - "uploadBytes": 0, - "downloadBytes": 108258132 - }, - { - "type": "intermediary", - "timeSeconds": 1.000107775, - "uploadBytes": 0, - "downloadBytes": 109028728 - }, - { - "type": "intermediary", - "timeSeconds": 1.000056261, - "uploadBytes": 0, - "downloadBytes": 109516304 - }, - { - "type": "intermediary", - "timeSeconds": 1.000119535, - "uploadBytes": 0, - "downloadBytes": 109114896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000211021, - "uploadBytes": 0, - "downloadBytes": 109243981 - }, - { - "type": "intermediary", - "timeSeconds": 1.000130571, - "uploadBytes": 0, - "downloadBytes": 109498119 - }, - { - "type": "intermediary", - "timeSeconds": 1.000045991, - "uploadBytes": 0, - "downloadBytes": 109683072 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013668, - "uploadBytes": 0, - "downloadBytes": 109859456 - }, - { - "type": "intermediary", - "timeSeconds": 1.000057904, - "uploadBytes": 0, - "downloadBytes": 110287232 - }, - { - "type": "intermediary", - "timeSeconds": 1.000260596, - "uploadBytes": 0, - "downloadBytes": 110197248 - }, - { - "type": "intermediary", - "timeSeconds": 1.000030761, - "uploadBytes": 0, - "downloadBytes": 110473984 - }, - { - "type": "intermediary", - "timeSeconds": 1.000135935, - "uploadBytes": 0, - "downloadBytes": 110570496 - }, - { - "type": "intermediary", - "timeSeconds": 1.000248491, - "uploadBytes": 0, - "downloadBytes": 111226624 - }, - { - "type": "intermediary", - "timeSeconds": 1.000199385, - "uploadBytes": 0, - "downloadBytes": 111553280 - }, - { - "type": "intermediary", - "timeSeconds": 1.000002086, - "uploadBytes": 0, - "downloadBytes": 57661756 - }, - { - "type": "intermediary", - "timeSeconds": 1.000016826, - "uploadBytes": 0, - "downloadBytes": 114403852 - }, - { - "type": "intermediary", - "timeSeconds": 1.000099014, - "uploadBytes": 0, - "downloadBytes": 115322460 - }, - { - "type": "intermediary", - "timeSeconds": 1.00007248, - "uploadBytes": 0, - "downloadBytes": 115174712 - }, - { - "type": "intermediary", - "timeSeconds": 1.000059636, - "uploadBytes": 0, - "downloadBytes": 115108044 - }, - { - "type": "intermediary", - "timeSeconds": 1.00003015, - "uploadBytes": 0, - "downloadBytes": 115554672 - }, - { - "type": "intermediary", - "timeSeconds": 1.000309765, - "uploadBytes": 0, - "downloadBytes": 115809452 - }, - { - "type": "intermediary", - "timeSeconds": 1.000193507, - "uploadBytes": 0, - "downloadBytes": 105023972 - }, - { - "type": "intermediary", - "timeSeconds": 1.000037536, - "uploadBytes": 0, - "downloadBytes": 81422844 - }, - { - "type": "intermediary", - "timeSeconds": 1.000097001, - "uploadBytes": 0, - "downloadBytes": 81869996 - }, - { - "type": "intermediary", - "timeSeconds": 1.000154377, - "uploadBytes": 0, - "downloadBytes": 81914544 - }, - { - "type": "intermediary", - "timeSeconds": 1.000036663, - "uploadBytes": 0, - "downloadBytes": 81988096 - }, - { - "type": "intermediary", - "timeSeconds": 1.000231418, - "uploadBytes": 0, - "downloadBytes": 82264832 - }, - { - "type": "intermediary", - "timeSeconds": 1.000372487, - "uploadBytes": 0, - "downloadBytes": 82708992 - }, - { - "type": "intermediary", - "timeSeconds": 1.000049333, - "uploadBytes": 0, - "downloadBytes": 83239409 - }, - { - "type": "intermediary", - "timeSeconds": 1.00002656, - "uploadBytes": 0, - "downloadBytes": 83530255 - }, - { - "type": "intermediary", - "timeSeconds": 1.000297574, - "uploadBytes": 0, - "downloadBytes": 83411840 - }, - { - "type": "intermediary", - "timeSeconds": 1.00000979, - "uploadBytes": 0, - "downloadBytes": 83619456 - }, - { - "type": "intermediary", - "timeSeconds": 1.000188489, - "uploadBytes": 0, - "downloadBytes": 83922944 - }, - { - "type": "intermediary", - "timeSeconds": 1.000082008, - "uploadBytes": 0, - "downloadBytes": 44349168 - }, - { - "type": "intermediary", - "timeSeconds": 1.00350515, - "uploadBytes": 0, - "downloadBytes": 74884820 - }, - { - "type": "intermediary", - "timeSeconds": 1.000080777, - "uploadBytes": 0, - "downloadBytes": 75840673 - }, - { - "type": "intermediary", - "timeSeconds": 1.000213608, - "uploadBytes": 0, - "downloadBytes": 74851727 - }, - { - "type": "intermediary", - "timeSeconds": 1.000039081, - "uploadBytes": 0, - "downloadBytes": 75094372 - }, - { - "type": "intermediary", - "timeSeconds": 1.000131395, - "uploadBytes": 0, - "downloadBytes": 75331380 - }, - { - "type": "intermediary", - "timeSeconds": 1.000237599, - "uploadBytes": 0, - "downloadBytes": 76307908 - }, - { - "type": "intermediary", - "timeSeconds": 1.000250167, - "uploadBytes": 0, - "downloadBytes": 75729085 - }, - { - "type": "intermediary", - "timeSeconds": 1.000137504, - "uploadBytes": 0, - "downloadBytes": 75969811 - }, - { - "type": "intermediary", - "timeSeconds": 1.000133088, - "uploadBytes": 0, - "downloadBytes": 76567228 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003324, - "uploadBytes": 0, - "downloadBytes": 77034452 - }, - { - "type": "intermediary", - "timeSeconds": 1.000030293, - "uploadBytes": 0, - "downloadBytes": 76729933 - }, - { - "type": "intermediary", - "timeSeconds": 1.000182351, - "uploadBytes": 0, - "downloadBytes": 76884759 - }, - { - "type": "intermediary", - "timeSeconds": 1.000185179, - "uploadBytes": 0, - "downloadBytes": 77457904 - }, - { - "type": "intermediary", - "timeSeconds": 1.00036577, - "uploadBytes": 0, - "downloadBytes": 77581820 - }, - { - "type": "intermediary", - "timeSeconds": 1.000740537, - "uploadBytes": 0, - "downloadBytes": 77124608 - }, - { - "type": "intermediary", - "timeSeconds": 1.000064931, - "uploadBytes": 0, - "downloadBytes": 77883520 - }, - { - "type": "intermediary", - "timeSeconds": 1.000118303, - "uploadBytes": 0, - "downloadBytes": 77966720 - }, - { - "type": "intermediary", - "timeSeconds": 1.000028718, - "uploadBytes": 0, - "downloadBytes": 78097792 - }, - { - "type": "intermediary", - "timeSeconds": 1.000094195, - "uploadBytes": 0, - "downloadBytes": 51520889 - }, - { - "type": "intermediary", - "timeSeconds": 1.000052576, - "uploadBytes": 0, - "downloadBytes": 111872787 - }, - { - "type": "intermediary", - "timeSeconds": 1.000013397, - "uploadBytes": 0, - "downloadBytes": 111743116 - }, - { - "type": "intermediary", - "timeSeconds": 1.000004728, - "uploadBytes": 0, - "downloadBytes": 110261204 - }, - { - "type": "intermediary", - "timeSeconds": 1.000105285, - "uploadBytes": 0, - "downloadBytes": 112188028 - }, - { - "type": "intermediary", - "timeSeconds": 1.000340675, - "uploadBytes": 0, - "downloadBytes": 111819948 - }, - { - "type": "intermediary", - "timeSeconds": 1.000205075, - "uploadBytes": 0, - "downloadBytes": 111145952 - }, - { - "type": "intermediary", - "timeSeconds": 1.000027463, - "uploadBytes": 0, - "downloadBytes": 112491424 - }, - { - "type": "intermediary", - "timeSeconds": 1.000145215, - "uploadBytes": 0, - "downloadBytes": 112992816 - }, - { - "type": "intermediary", - "timeSeconds": 1.000084428, - "uploadBytes": 0, - "downloadBytes": 91007460 - }, - { - "type": "intermediary", - "timeSeconds": 1.000761761, - "uploadBytes": 0, - "downloadBytes": 78529880 - }, - { - "type": "intermediary", - "timeSeconds": 1.000862967, - "uploadBytes": 0, - "downloadBytes": 43525760 - }, - { - "type": "intermediary", - "timeSeconds": 1.00005513, - "uploadBytes": 0, - "downloadBytes": 55241216 - }, - { - "type": "intermediary", - "timeSeconds": 1.000030293, - "uploadBytes": 0, - "downloadBytes": 56192241 - }, - { - "type": "intermediary", - "timeSeconds": 1.000111766, - "uploadBytes": 0, - "downloadBytes": 56128015 - }, - { - "type": "intermediary", - "timeSeconds": 1.000057792, - "uploadBytes": 0, - "downloadBytes": 56461696 - }, - { - "type": "intermediary", - "timeSeconds": 1.000242071, - "uploadBytes": 0, - "downloadBytes": 56813824 - }, - { - "type": "intermediary", - "timeSeconds": 1.000036598, - "uploadBytes": 0, - "downloadBytes": 57062400 - }, - { - "type": "intermediary", - "timeSeconds": 1.000213028, - "uploadBytes": 0, - "downloadBytes": 57362304 - }, - { - "type": "intermediary", - "timeSeconds": 1.000024545, - "uploadBytes": 0, - "downloadBytes": 49331284 - }, - { - "type": "intermediary", - "timeSeconds": 1.000677294, - "uploadBytes": 0, - "downloadBytes": 107492676 - }, - { - "type": "intermediary", - "timeSeconds": 1.000144644, - "uploadBytes": 0, - "downloadBytes": 106068896 - }, - { - "type": "intermediary", - "timeSeconds": 1.000005734, - "uploadBytes": 0, - "downloadBytes": 107074808 - }, - { - "type": "intermediary", - "timeSeconds": 1.000268012, - "uploadBytes": 0, - "downloadBytes": 106940617 - }, - { - "type": "intermediary", - "timeSeconds": 1.000104899, - "uploadBytes": 0, - "downloadBytes": 107756731 - }, - { - "type": "intermediary", - "timeSeconds": 1.000069525, - "uploadBytes": 0, - "downloadBytes": 107870564 - }, - { - "type": "intermediary", - "timeSeconds": 1.000003547, - "uploadBytes": 0, - "downloadBytes": 107154464 - }, - { - "type": "intermediary", - "timeSeconds": 1.000124456, - "uploadBytes": 0, - "downloadBytes": 108745404 - }, - { - "type": "intermediary", - "timeSeconds": 1.000037923, - "uploadBytes": 0, - "downloadBytes": 79755620 - }, - { - "type": "intermediary", - "timeSeconds": 1.005694223, - "uploadBytes": 0, - "downloadBytes": 76630220 - }, - { - "type": "intermediary", - "timeSeconds": 1.000006999, - "uploadBytes": 0, - "downloadBytes": 76239836 - }, - { - "type": "intermediary", - "timeSeconds": 1.000209671, - "uploadBytes": 0, - "downloadBytes": 75660928 - }, - { - "type": "intermediary", - "timeSeconds": 1.00021249, - "uploadBytes": 0, - "downloadBytes": 75910016 - }, - { - "type": "intermediary", - "timeSeconds": 1.000220478, - "uploadBytes": 0, - "downloadBytes": 77087232 - }, - { - "type": "intermediary", - "timeSeconds": 1.00012585, - "uploadBytes": 0, - "downloadBytes": 76390257 - }, - { - "type": "intermediary", - "timeSeconds": 1.000127895, - "uploadBytes": 0, - "downloadBytes": 76724111 - }, - { - "type": "intermediary", - "timeSeconds": 1.000205487, - "uploadBytes": 0, - "downloadBytes": 77315840 - }, - { - "type": "intermediary", - "timeSeconds": 1.000161359, - "uploadBytes": 0, - "downloadBytes": 77478784 - }, - { - "type": "intermediary", - "timeSeconds": 1.000969952, - "uploadBytes": 0, - "downloadBytes": 57042939 - }, - { - "type": "intermediary", - "timeSeconds": 1.000124711, - "uploadBytes": 0, - "downloadBytes": 89084533 - }, - { - "type": "intermediary", - "timeSeconds": 1.000058787, - "uploadBytes": 0, - "downloadBytes": 77035316 - }, - { - "type": "intermediary", - "timeSeconds": 1.000239081, - "uploadBytes": 0, - "downloadBytes": 76413564 - }, - { - "type": "intermediary", - "timeSeconds": 1.000188494, - "uploadBytes": 0, - "downloadBytes": 77018920 - }, - { - "type": "intermediary", - "timeSeconds": 1.000039185, - "uploadBytes": 0, - "downloadBytes": 77688120 - }, - { - "type": "intermediary", - "timeSeconds": 1.000212236, - "uploadBytes": 0, - "downloadBytes": 77821748 - }, - { - "type": "intermediary", - "timeSeconds": 1.0000584, - "uploadBytes": 0, - "downloadBytes": 77831900 - }, - { - "type": "intermediary", - "timeSeconds": 1.000019169, - "uploadBytes": 0, - "downloadBytes": 78498008 - }, - { - "type": "intermediary", - "timeSeconds": 1.000020397, - "uploadBytes": 0, - "downloadBytes": 78455049 - }, - { - "type": "intermediary", - "timeSeconds": 1.000026115, - "uploadBytes": 0, - "downloadBytes": 78627668 - }, - { - "type": "intermediary", - "timeSeconds": 1.000096279, - "uploadBytes": 0, - "downloadBytes": 78879943 - }, - { - "type": "intermediary", - "timeSeconds": 1.000223021, - "uploadBytes": 0, - "downloadBytes": 79037828 - }, - { - "type": "intermediary", - "timeSeconds": 1.000072632, - "uploadBytes": 0, - "downloadBytes": 79670113 - }, - { - "type": "intermediary", - "timeSeconds": 1.000050549, - "uploadBytes": 0, - "downloadBytes": 79418127 - }, - { - "type": "intermediary", - "timeSeconds": 1.00038353, - "uploadBytes": 0, - "downloadBytes": 79679360 - }, - { - "type": "intermediary", - "timeSeconds": 1.000096935, - "uploadBytes": 0, - "downloadBytes": 80059392 - }, - { - "type": "intermediary", - "timeSeconds": 1.000094774, - "uploadBytes": 0, - "downloadBytes": 80534769 - }, - { - "type": "intermediary", - "timeSeconds": 1.000036737, - "uploadBytes": 0, - "downloadBytes": 80348288 - } - ], - "implementation": "go-libp2p", - "version": "v0.42", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 31981568 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 200671232 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 243859456 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256835572 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 255262732 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 257818624 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258277376 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258801664 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 257490932 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 252968972 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 257556480 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258539520 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258932736 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258867200 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258539520 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258736116 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258932748 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259194880 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258736128 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 39321600 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 198574080 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258146304 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 206897152 - }, - { - "type": "intermediary", - "timeSeconds": 1.009, - "uploadBytes": 0, - "downloadBytes": 185466880 - }, - { - "type": "intermediary", - "timeSeconds": 1.007, - "uploadBytes": 0, - "downloadBytes": 116785152 - }, - { - "type": "intermediary", - "timeSeconds": 1.008, - "uploadBytes": 0, - "downloadBytes": 121372672 - }, - { - "type": "intermediary", - "timeSeconds": 1.007, - "uploadBytes": 0, - "downloadBytes": 125304832 - }, - { - "type": "intermediary", - "timeSeconds": 1.007, - "uploadBytes": 0, - "downloadBytes": 128581632 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 130613248 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 131203072 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 133038080 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 134152180 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 136445964 - }, - { - "type": "intermediary", - "timeSeconds": 1.002, - "uploadBytes": 0, - "downloadBytes": 123600896 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 99090432 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 102498304 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 106037248 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 108396544 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 57737216 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 220135424 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259981312 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263847936 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266469376 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262668288 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 255328256 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264110080 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265355264 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265551872 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266928128 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266338304 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265879552 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266600448 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266797056 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265945088 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265420800 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 249626624 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 243990528 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 60751872 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 233046016 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256311296 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 254803968 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 260571136 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261226496 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 254345216 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258605056 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258736128 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 255787008 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 253296640 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 244449280 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 254148596 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 257425420 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256180224 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256376832 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259653632 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262799348 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261488652 - }, - { - "type": "intermediary", - "timeSeconds": 1.005, - "uploadBytes": 0, - "downloadBytes": 53346304 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 230293504 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 252313588 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264699916 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264044544 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261816320 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261029888 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259457024 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 257097728 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 252313600 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 260702196 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 229310476 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 255721460 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259194880 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 246546444 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 254214132 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258342924 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261292032 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259194880 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 59637760 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 237568000 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 254410752 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262078464 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262733824 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261685248 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261881856 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261095424 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259719168 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256114688 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262864884 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262078476 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 260833280 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262340608 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263389184 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263454720 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262733824 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263389184 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262799360 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 54657024 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 234225664 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263192564 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262340620 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264241152 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264634356 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264110092 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264110068 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264241164 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 254476288 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264372224 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263651316 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264241164 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264699904 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264437760 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263979008 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263979008 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264634356 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263782412 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 63897600 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 245039104 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 254869504 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265093120 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 260833280 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259850228 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 264699916 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 270598144 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 267386880 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 251527168 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265551872 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262209536 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 267780096 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256311296 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256376832 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256180224 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 267386880 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 271187968 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256180224 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 51838976 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 231800832 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 252510208 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 255131648 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 260374528 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259588096 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 260767744 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 258539520 - }, - { - "type": "intermediary", - "timeSeconds": 1.002, - "uploadBytes": 0, - "downloadBytes": 258998272 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259325952 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259063808 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259915776 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 257163264 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256638976 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 259325952 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 256376832 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 257163264 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 253427712 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 250806272 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 28901376 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 233439232 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266141696 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266338304 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262340608 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 267255808 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263716852 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261881868 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265945088 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261423104 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 262995968 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 261685248 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266010624 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 267124736 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266600448 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 266534912 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 267059200 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 265945088 - }, - { - "type": "intermediary", - "timeSeconds": 1.001, - "uploadBytes": 0, - "downloadBytes": 263192564 - } - ], - "implementation": "js-libp2p", - "version": "v2.8", - "transportStack": "tcp" - } - ], - "parameters": { - "uploadBytes": 0, - "downloadBytes": 9007199254740991 - } - }, - { - "name": "Connection establishment + 1 byte round trip latencies", - "unit": "s", - "results": [ - { - "result": [ - { - "type": "final", - "timeSeconds": 0.131903762, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12842527, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.131350367, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128081984, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128996325, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128110925, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12794738, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129819129, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.131892157, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126021521, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129468053, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.133217212, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128979589, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127962365, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128279388, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130088748, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128987838, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130086154, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129228102, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.131822363, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.13009221, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129637543, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12781764, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128316856, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129446683, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128480803, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127902464, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129312724, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127384453, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.131465076, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130130768, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129669729, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.124872001, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128802579, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129146431, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127986157, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126916254, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.124938745, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129056892, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129926974, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130595085, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130091411, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130002143, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.131154305, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128889142, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.132220244, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127239794, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130257972, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129554872, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129031327, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130307184, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.131990917, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129015671, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128476237, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128563619, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12784629, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128636643, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129190621, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130977725, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127041116, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123639866, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130367424, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123722947, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129085093, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126385607, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128833866, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.125071015, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12823853, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127958447, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128429519, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130070641, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129635168, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.124945454, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.13062234, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129101832, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130332188, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127120286, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12793999, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130280213, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130105659, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130396532, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128253247, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130652095, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129966443, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129793388, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126995551, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130886271, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128125454, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129144274, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129152015, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127285842, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129104082, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128936507, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.131429201, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129990812, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12520872, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12950441, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128771096, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.124769577, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126904367, - "uploadBytes": 1, - "downloadBytes": 1 - } - ], - "implementation": "quic-go", - "version": "v0.45", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "final", - "timeSeconds": 0.190243808, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192559946, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189067085, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189948001, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188182113, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189482971, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18624071, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192849077, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191334743, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189180397, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190627043, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189690407, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193648283, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191870145, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19007902, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189689801, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190379596, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189630753, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190685874, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190083444, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187530838, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185348151, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185247032, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191181604, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193471306, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189395605, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190864179, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187960516, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188072058, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192802271, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190364935, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188860672, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190153904, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190839932, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191427481, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187934929, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194561818, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189496, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189706496, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189018395, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188319347, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.184182235, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195037506, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.1872726, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192327332, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190852886, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191280459, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189105384, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187938138, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194935043, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18981472, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192390074, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19315906, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194143648, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19220818, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193847745, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192098068, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187163538, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19188176, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19090263, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19313734, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188187288, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.184614994, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190082686, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188392935, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189143898, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188164888, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190758296, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189974313, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191967079, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187644142, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191945042, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191209759, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188409271, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193438528, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191364828, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189616234, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190600662, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.184533615, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193435275, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19136684, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191170946, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194758731, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191611223, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191957194, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192057452, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190264611, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187523958, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18986459, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192915153, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190059841, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195791353, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191983344, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187723465, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.184827251, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.186173818, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188894197, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189433713, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.1910137, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190489868, - "uploadBytes": 1, - "downloadBytes": 1 - } - ], - "implementation": "rust-libp2p", - "version": "v0.55", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "final", - "timeSeconds": 0.127780884, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123285391, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126652733, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12904142, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127229635, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.132337605, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126797628, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129513294, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123714469, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127737714, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127739883, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128013942, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129291013, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126048585, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129035577, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126314795, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129479552, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128022272, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128064804, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128282436, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12623224, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129215905, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127494444, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129263442, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129061962, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130813824, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128775257, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.125820754, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123294697, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.1269336, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128324612, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129613954, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126761666, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123471234, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127366197, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130582148, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127631313, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12692754, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130448063, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127541251, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.125985225, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126903687, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127038592, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128139613, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128399079, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123462873, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12938056, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.120829043, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129080731, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126968473, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126854422, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12995815, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.125758056, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.121101631, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129098518, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127499255, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128358766, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127377272, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.124400873, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129266584, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128440338, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126531686, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130455107, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126583941, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127353183, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.13057933, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12682657, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127173281, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127960772, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128832228, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128518065, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127700967, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127355468, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130527016, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130287559, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130238304, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129287058, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128617877, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127478397, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127697113, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123254075, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129778156, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.125251138, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128377822, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128485682, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.12839345, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129436966, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129578444, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129285963, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.123804973, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.126159499, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129194643, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127277817, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130133946, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.128113761, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129281498, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129803199, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.127143333, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.130399172, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.129871221, - "uploadBytes": 1, - "downloadBytes": 1 - } - ], - "implementation": "rust-libp2p", - "version": "v0.55", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "final", - "timeSeconds": 0.184925412, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.184754154, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190074536, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.186298426, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191212174, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192461906, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187828982, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189492314, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193935615, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18967518, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192732641, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.1914901, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18891385, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185327537, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187783702, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190759716, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190449918, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194113799, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191484415, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191518916, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.182964482, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187308316, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187558263, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190976797, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189044084, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188525543, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.179311165, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191392291, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190742982, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193719529, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189919076, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189997008, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18755474, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192748019, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190061953, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.184464097, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.183744313, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190201225, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185725058, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.182723828, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188906348, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.184710564, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190100502, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187393647, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189563124, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191620037, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192455686, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187547809, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189856388, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19052121, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18878219, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.183667714, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185102879, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191561045, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190983632, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192940844, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190558126, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193088285, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192119477, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190058594, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193761855, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18721233, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191803364, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191179154, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188604652, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188467503, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190324948, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189951772, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188348663, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185452149, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194454441, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189543581, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194496141, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193364312, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185788771, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18841585, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190530746, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194219084, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193529009, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18898971, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192479354, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187913631, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189936208, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189546739, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190263874, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187837918, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193419576, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193835874, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.183231528, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188277639, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193732071, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188927091, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190095788, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192120947, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18967492, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.186389501, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190096641, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192666892, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.18841612, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190987715, - "uploadBytes": 1, - "downloadBytes": 1 - } - ], - "implementation": "https", - "version": "v0.1", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "final", - "timeSeconds": 0.315202585, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318189292, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315896249, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317909705, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.383447292, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.378426705, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.375427206, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.31666589, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316031277, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320044303, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.375498344, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316364812, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.325248037, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317510832, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.323965943, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.31353544, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317144303, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.32121716, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.37903113, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316682788, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316625825, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.307271207, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.375695432, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.307785063, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318517063, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.306081001, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.314624338, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.384113592, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313598516, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315886113, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.31670643, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315968778, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317984333, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.386800864, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317944608, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.384155625, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.325507062, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.321063794, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.387550874, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.379835808, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.37929218, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.306466961, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.377570493, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316682213, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.314959213, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317154358, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318801819, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317971718, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318049481, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.321664924, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.323915751, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315363227, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.377990402, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.3152896, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.322125285, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.388815856, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.324338238, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.378385729, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318867267, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313754631, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318169549, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.31594688, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315116637, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.321883605, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.38076495, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316692323, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.314713823, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318450544, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313611498, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320775267, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.312448502, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.321112948, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320533997, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.374488777, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316900391, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.383976005, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.305602221, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.379992662, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320053153, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313594471, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.321071565, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.321610402, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318747081, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.368109771, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.382790399, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317649556, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318205698, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313680986, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.388180829, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.314737174, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.309520482, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.380820758, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.324594867, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313396308, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.323225766, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317574211, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320329968, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317178601, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315808107, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316603901, - "uploadBytes": 1, - "downloadBytes": 1 - } - ], - "implementation": "go-libp2p", - "version": "v0.41", - "transportStack": "tcp" - }, - { - "result": [ - { - "type": "final", - "timeSeconds": 0.194460856, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192530461, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189677156, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194948387, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.197843531, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.188132384, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190912411, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192857581, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191752564, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191740162, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190946157, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19557139, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196731803, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19475216, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192728438, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193210701, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195673556, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194437143, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19517622, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196366731, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196902863, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19157391, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192657108, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190464849, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193386263, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195157209, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196585387, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194728263, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187480793, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189005282, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195128402, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191385417, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194127192, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194495594, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195340399, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192805631, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.185516598, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194339777, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193815196, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192165671, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189323717, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194987755, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19476764, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196676641, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193644183, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194840428, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195170666, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194664341, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196691242, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193631463, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192727762, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190694474, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193076217, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192400863, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195071525, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196479071, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187522259, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195923299, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194694541, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191101233, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195533142, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187916216, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193221708, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196527197, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191151955, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193088292, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195263048, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194623729, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194024627, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.181840386, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193680628, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193324862, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195892498, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19260612, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191501242, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196228195, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190570139, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191319224, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194212331, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.190356706, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192940695, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194263405, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19473069, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.196446879, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189685968, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193871659, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191013106, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195275438, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.187659261, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.19296321, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.189496597, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195074949, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192735306, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192216187, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193051754, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.195239368, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.191650587, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.193451566, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.194346227, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.192220162, - "uploadBytes": 1, - "downloadBytes": 1 - } - ], - "implementation": "go-libp2p", - "version": "v0.41", - "transportStack": "quic-v1" - }, - { - "result": [ - { - "type": "final", - "timeSeconds": 0.327899306, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.378418167, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.309343409, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.325105887, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317831031, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320916566, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.304935153, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315901564, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.383085036, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.386120434, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.323302227, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.308723762, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313585724, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317631211, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313509009, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316446105, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.380308193, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.375560298, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.310521316, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.387709122, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316295371, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.325141397, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320059467, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.377138197, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.36456487, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.379708028, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.376849806, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313532987, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.319697404, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.308074589, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316164287, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.322843546, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.377810593, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.32411416, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.307886741, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.373459632, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320112976, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320360581, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317099758, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317260489, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.322525511, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320739162, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.384111701, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.389807326, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.323185118, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320693738, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.325275288, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.319520274, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.308266534, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315802875, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.319078473, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.380425131, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.388506504, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317065181, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.311772469, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.308439559, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.38312228, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320558832, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.382627084, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.38047294, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.375650101, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320831469, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.321050114, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.322180701, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.314174892, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.319806553, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.322060846, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.318067884, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.373326307, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.31377909, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.32422995, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.38352129, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313594572, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.314751663, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.323909061, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.31964407, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.381050217, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.319556804, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.322137319, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.317813524, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.313447704, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.320606656, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.325250812, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.305840104, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.316764365, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.381248632, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.312856678, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.373949775, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315731397, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.375500892, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.315617031, - "uploadBytes": 1, - "downloadBytes": 1 - }, - { - "type": "final", - "timeSeconds": 0.32303461, - "uploadBytes": 1, - "downloadBytes": 1 + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 281739264 }, { - "type": "final", - "timeSeconds": 0.319218803, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 284295168 }, { - "type": "final", - "timeSeconds": 0.317926741, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 283574272 }, { - "type": "final", - "timeSeconds": 0.386311015, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 283115520 }, { - "type": "final", - "timeSeconds": 0.310586494, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 268959744 }, { - "type": "final", - "timeSeconds": 0.318114069, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 275644416 }, { - "type": "final", - "timeSeconds": 0.318178327, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 269221888 }, { - "type": "final", - "timeSeconds": 0.383077026, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 274137088 }, { - "type": "final", - "timeSeconds": 0.308440939, - "uploadBytes": 1, - "downloadBytes": 1 + "type": "intermediary", + "timeSeconds": 1.001, + "uploadBytes": 0, + "downloadBytes": 269811712 } ], - "implementation": "go-libp2p", - "version": "v0.42", + "implementation": "js-libp2p", + "version": "v2.8-eventtarget", "transportStack": "tcp" - }, + } + ], + "parameters": { + "uploadBytes": 0, + "downloadBytes": 9007199254740991 + } + }, + { + "name": "Connection establishment + 1 byte round trip latencies", + "unit": "s", + "results": [ { "result": [ { "type": "final", - "timeSeconds": 0.186105172, + "timeSeconds": 0.428, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192851307, + "timeSeconds": 0.408, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194055778, + "timeSeconds": 0.394, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193199694, + "timeSeconds": 0.388, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.197474698, + "timeSeconds": 0.398, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192120449, + "timeSeconds": 0.425, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193655092, + "timeSeconds": 0.418, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.188039665, + "timeSeconds": 0.416, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190182343, + "timeSeconds": 0.414, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190815054, + "timeSeconds": 0.427, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192728111, + "timeSeconds": 0.418, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192167592, + "timeSeconds": 0.401, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.186607217, + "timeSeconds": 0.42, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190629916, + "timeSeconds": 0.414, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.196156264, + "timeSeconds": 0.4, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194044716, + "timeSeconds": 0.404, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195149155, + "timeSeconds": 0.423, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.189160706, + "timeSeconds": 0.389, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194584024, + "timeSeconds": 0.395, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194681837, + "timeSeconds": 0.393, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192025873, + "timeSeconds": 0.406, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194252038, + "timeSeconds": 0.421, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195125641, + "timeSeconds": 0.399, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.197444432, + "timeSeconds": 0.406, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193912103, + "timeSeconds": 0.417, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195434425, + "timeSeconds": 0.397, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194942884, + "timeSeconds": 0.41, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191163876, + "timeSeconds": 0.407, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.187476564, + "timeSeconds": 0.414, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.196528403, + "timeSeconds": 0.408, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190856712, + "timeSeconds": 0.409, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192197195, + "timeSeconds": 0.415, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194390539, + "timeSeconds": 0.411, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191225282, + "timeSeconds": 0.379, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190291275, + "timeSeconds": 0.42, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.188216347, + "timeSeconds": 0.412, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190085263, + "timeSeconds": 0.392, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194454722, + "timeSeconds": 0.416, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.198005253, + "timeSeconds": 0.393, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.189692288, + "timeSeconds": 0.405, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193108631, + "timeSeconds": 0.417, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191870025, + "timeSeconds": 0.4, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193116813, + "timeSeconds": 0.408, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.1926732, + "timeSeconds": 0.413, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190892258, + "timeSeconds": 0.413, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.188282991, + "timeSeconds": 0.406, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194480608, + "timeSeconds": 0.407, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191692419, + "timeSeconds": 0.406, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.19176784, + "timeSeconds": 0.42, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191994527, + "timeSeconds": 0.42, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193763406, + "timeSeconds": 0.401, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192738963, + "timeSeconds": 0.409, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192730252, + "timeSeconds": 0.414, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192632975, + "timeSeconds": 0.42, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190695154, + "timeSeconds": 0.394, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191117305, + "timeSeconds": 0.418, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193415602, + "timeSeconds": 0.419, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192744565, + "timeSeconds": 0.395, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190737911, + "timeSeconds": 0.408, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192895356, + "timeSeconds": 0.394, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193624319, + "timeSeconds": 0.416, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.196373743, + "timeSeconds": 0.42, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.1924331, + "timeSeconds": 0.396, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.185792739, + "timeSeconds": 0.415, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191493725, + "timeSeconds": 0.413, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195343528, + "timeSeconds": 0.41, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195505165, + "timeSeconds": 0.416, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194931907, + "timeSeconds": 0.422, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190846199, + "timeSeconds": 0.384, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193361135, + "timeSeconds": 0.415, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193246526, + "timeSeconds": 0.409, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195467197, + "timeSeconds": 0.404, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193265829, + "timeSeconds": 0.411, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191992023, + "timeSeconds": 0.401, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191898564, + "timeSeconds": 0.418, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194636216, + "timeSeconds": 0.407, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.196515557, + "timeSeconds": 0.412, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.189617625, + "timeSeconds": 0.417, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.187872314, + "timeSeconds": 0.399, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.191094519, + "timeSeconds": 0.423, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.185490616, + "timeSeconds": 0.416, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.187633275, + "timeSeconds": 0.415, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.1937595, + "timeSeconds": 0.394, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195104968, + "timeSeconds": 0.393, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.19308984, + "timeSeconds": 0.417, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.189954435, + "timeSeconds": 0.385, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194249778, + "timeSeconds": 0.384, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193452524, + "timeSeconds": 0.413, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.187950116, + "timeSeconds": 0.422, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.19472665, + "timeSeconds": 0.417, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.185735847, + "timeSeconds": 0.407, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.195756584, + "timeSeconds": 0.423, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192739017, + "timeSeconds": 0.42, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.192813499, + "timeSeconds": 0.406, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.194388263, + "timeSeconds": 0.419, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.193451909, + "timeSeconds": 0.419, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.186982655, + "timeSeconds": 0.394, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.19089508, + "timeSeconds": 0.394, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.19227069, + "timeSeconds": 0.41, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.190459811, + "timeSeconds": 0.401, "uploadBytes": 1, "downloadBytes": 1 } ], - "implementation": "go-libp2p", - "version": "v0.42", - "transportStack": "quic-v1" + "implementation": "js-libp2p", + "version": "v2.8", + "transportStack": "tcp" }, { "result": [ { "type": "final", - "timeSeconds": 0.434, + "timeSeconds": 0.361, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.419, + "timeSeconds": 0.348, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.407, + "timeSeconds": 0.337, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.404, + "timeSeconds": 0.356, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.416, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.408, + "timeSeconds": 0.341, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.405, + "timeSeconds": 0.345, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.338, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.425, + "timeSeconds": 0.344, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.427, + "timeSeconds": 0.342, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.409, + "timeSeconds": 0.342, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.425, + "timeSeconds": 0.41, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.418, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.415, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.424, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.355, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.407, + "timeSeconds": 0.355, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.345, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.42, + "timeSeconds": 0.357, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.415, + "timeSeconds": 0.32, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.413, + "timeSeconds": 0.335, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.413, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.404, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.416, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.351, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.425, + "timeSeconds": 0.357, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.419, + "timeSeconds": 0.338, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.356, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.42, + "timeSeconds": 0.338, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.423, + "timeSeconds": 0.337, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.429, + "timeSeconds": 0.322, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.418, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.418, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.328, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.422, + "timeSeconds": 0.34, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.423, + "timeSeconds": 0.339, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.425, + "timeSeconds": 0.339, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.408, + "timeSeconds": 0.321, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.428, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.42, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.406, + "timeSeconds": 0.331, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.409, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.418, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.415, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.419, + "timeSeconds": 0.353, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.419, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.338, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.419, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.348, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.423, + "timeSeconds": 0.346, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.406, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.427, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.425, + "timeSeconds": 0.33, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.342, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.42, + "timeSeconds": 0.329, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.405, + "timeSeconds": 0.33, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.422, + "timeSeconds": 0.351, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.348, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.416, + "timeSeconds": 0.351, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.412, + "timeSeconds": 0.345, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.334, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.426, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.425, + "timeSeconds": 0.351, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.428, + "timeSeconds": 0.353, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.413, + "timeSeconds": 0.345, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.424, + "timeSeconds": 0.331, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.424, + "timeSeconds": 0.343, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.337, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.417, + "timeSeconds": 0.348, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.416, + "timeSeconds": 0.342, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.34, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.408, + "timeSeconds": 0.336, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.42, + "timeSeconds": 0.343, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.42, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.403, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.416, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.423, + "timeSeconds": 0.351, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.414, + "timeSeconds": 0.33, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.419, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.421, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.419, + "timeSeconds": 0.352, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.408, + "timeSeconds": 0.351, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.413, + "timeSeconds": 0.329, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.407, + "timeSeconds": 0.337, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.413, + "timeSeconds": 0.354, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.422, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.416, + "timeSeconds": 0.35, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.412, + "timeSeconds": 0.341, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.425, + "timeSeconds": 0.347, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.415, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.418, + "timeSeconds": 0.349, "uploadBytes": 1, "downloadBytes": 1 }, { "type": "final", - "timeSeconds": 0.413, + "timeSeconds": 0.346, "uploadBytes": 1, "downloadBytes": 1 } ], "implementation": "js-libp2p", - "version": "v2.8", + "version": "v2.8-eventtarget", "transportStack": "tcp" } ], @@ -25999,141 +5836,117 @@ "pings": { "unit": "s", "results": [ - 0.069, - 0.0686, - 0.0689, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.12, - 0.0633, - 0.06620000000000001, - 0.0638, - 0.0634, - 0.0635, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.432, - 0.0636, - 0.0633, - 0.0633, - 0.0634, - 0.0633, - 0.0633, - 0.0638, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0636, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0634, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633, - 0.0633 + 0.0681, + 0.0681, + 0.0678, + 0.0678, + 0.0678, + 0.0678, + 0.0678, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0629, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.376, + 0.063, + 0.0626, + 0.063, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0627, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626, + 0.0626 ] }, "iperf": { "unit": "bit/s", "results": [ - 2230000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, + 1990000000, 4780000000, 4790000000, 4780000000, 4790000000, 4780000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4780000000, - 4790000000, 4780000000, 4790000000, 4780000000, @@ -26146,26 +5959,50 @@ 4790000000, 4780000000, 4790000000, - 4650000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, - 4780000000, - 4790000000, 4780000000, 4790000000, 4780000000, - 4790000000, + 4690000000, + 3740000000, + 3890000000, + 4070000000.0000005, + 4170000000, + 4300000000, + 4420000000, + 4530000000, + 4600000000, + 4710000000, + 4770000000, 4780000000, 4790000000, 4780000000, 4780000000, 4790000000, 4780000000, - 4740000000, - 4730000000 + 4400000000, + 3620000000, + 3700000000, + 3790000000, + 3880000000, + 3930000000, + 3980000000, + 4050000000, + 4099999999.9999995, + 4120000000, + 4160000000, + 4200000000, + 4230000000.0000005, + 4240000000, + 4250000000, + 4280000000.0000005, + 4280000000.0000005, + 4269999999.9999995, + 4300000000, + 4290000000, + 4280000000.0000005, + 4300000000, + 4420000000, + 4400000000 ] } } \ No newline at end of file diff --git a/perf/runner/versionsInput.json b/perf/runner/versionsInput.json index 186daffa7..64a4e02d6 100644 --- a/perf/runner/versionsInput.json +++ b/perf/runner/versionsInput.json @@ -1,44 +1,13 @@ [ { - "id": "v0.45", - "implementation": "quic-go", - "transportStacks": [ - "quic-v1" - ] - }, - { - "id": "v0.55", - "implementation": "rust-libp2p", - "transportStacks": [ - "tcp", - "quic-v1" - ] - }, - { - "id": "v0.1", - "implementation": "https", + "id": "v2.8", + "implementation": "js-libp2p", "transportStacks": [ "tcp" ] }, { - "id": "v0.41", - "implementation": "go-libp2p", - "transportStacks": [ - "tcp", - "quic-v1" - ] - }, - { - "id": "v0.42", - "implementation": "go-libp2p", - "transportStacks": [ - "tcp", - "quic-v1" - ] - }, - { - "id": "v2.8", + "id": "v2.8-eventtarget", "implementation": "js-libp2p", "transportStacks": [ "tcp"