diff --git a/.aegir.js b/.aegir.js deleted file mode 100644 index 9a48402..0000000 --- a/.aegir.js +++ /dev/null @@ -1,12 +0,0 @@ - -/** @type {import('aegir/types').PartialOptions} */ -export default { - build: { - bundlesizeMax: '18kB' - }, - dependencyCheck: { - ignore: [ - 'undici' // required by http-cookie-agent - ] - } -} diff --git a/.cspell.json b/.cspell.json new file mode 100644 index 0000000..ce02f35 --- /dev/null +++ b/.cspell.json @@ -0,0 +1,11 @@ +{ + "import": [ + "./node_modules/aegir/cspell.json" + ], + "dictionaries": ["project"], + "dictionaryDefinitions": [{ + "name": "project", + "path": "./.github/dictionary.txt", + "addWords": true + }] +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d401a77..17d7e00 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -8,4 +8,17 @@ updates: open-pull-requests-limit: 20 commit-message: prefix: "deps" - prefix-development: "deps(dev)" + prefix-development: "chore" + groups: + libp2p-deps: + patterns: + - "*libp2p*" + - "*multiformats*" + - "*blockstore*" + - "*datastore*" +- package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: chore diff --git a/.github/dictionary.txt b/.github/dictionary.txt new file mode 100644 index 0000000..bd2f248 --- /dev/null +++ b/.github/dictionary.txt @@ -0,0 +1,3 @@ +undici +httponly +initializable diff --git a/.github/workflows/semantic-pull-request.yml b/.github/workflows/semantic-pull-request.yml index bd00f09..8c0b9ea 100644 --- a/.github/workflows/semantic-pull-request.yml +++ b/.github/workflows/semantic-pull-request.yml @@ -9,4 +9,4 @@ on: jobs: main: - uses: pl-strflt/.github/.github/workflows/reusable-semantic-pull-request.yml@v0.3 + uses: ipdxco/unified-github-workflows/.github/workflows/reusable-semantic-pull-request.yml@v1 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 16d65d7..1f9d6b8 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -3,6 +3,7 @@ name: Close and mark stale issue on: schedule: - cron: '0 0 * * *' + workflow_dispatch: permissions: issues: write @@ -10,4 +11,4 @@ permissions: jobs: stale: - uses: pl-strflt/.github/.github/workflows/reusable-stale-issue.yml@v0.3 + uses: ipdxco/unified-github-workflows/.github/workflows/reusable-stale-issue.yml@v1 diff --git a/.github/workflows/test-examples.yml b/.github/workflows/test-examples.yml deleted file mode 100644 index 807ecf4..0000000 --- a/.github/workflows/test-examples.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: test examples -on: - push: - branches: - - main - pull_request: - branches: - - "**" - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - run: npm i - working-directory: ./examples - - uses: ipfs/aegir/actions/cache-node-modules@main - with: - directories: | - ./examples/node_modules - - test-examples: - needs: build - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 - with: - node-version: lts/* - - uses: ipfs/aegir/actions/cache-node-modules@main - with: - directories: | - ./examples/node_modules - - uses: actions/setup-go@v5 - - run: go build -o test-runner main.go - working-directory: ./examples/test-runner - - run: ../test-runner/test-runner -hasProxy - working-directory: ./examples/go-libp2p-http-proxy - - run: ../test-runner/test-runner - working-directory: ./examples/js-libp2p-client-and-node-server/ - - run: ../test-runner/test-runner - working-directory: ./examples/two-js-peers - - run: ./runTest.sh - working-directory: ./examples/peer-id-auth diff --git a/.gitignore b/.gitignore index 7ad9e67..f115d26 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,5 @@ node_modules package-lock.json yarn.lock .vscode +.tmp-compiled-docs +tsconfig-doc-check.aegir.json diff --git a/README.md b/README.md index 04c65b8..d4e4cf5 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ -# @libp2p/http-fetch +# @libp2p/http [![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-http-fetch.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http-fetch) -[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http-fetch/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http-fetch/actions/workflows/js-test-and-release.yml?query=branch%3Amain) +[![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) -> Implementation of the WHATWG Fetch API on libp2p streams +> Accept HTTP requests over libp2p streams and/or use libp2p protocols over HTTP # About @@ -24,62 +24,67 @@ repo and examine the changes made. --> -http implements the WHATWG [Fetch -api](https://fetch.spec.whatwg.org). It can be used as a drop in replacement -for the browser's fetch function. It supports http, https, and multiaddr -URIs. Use HTTP in p2p networks. - -## Example - -See the `examples/` for full examples of how to use the HTTP service. - -```typescript -import { createLibp2p } from 'libp2p' -import { http } from '@libp2p/http-fetch' - -const node = await createLibp2p({ - // other options ... - services: { - http: http() - } -}) - -await node.start() - -// Make an http request to a libp2p peer -let resp = await node.services.http.fetch('multiaddr:/dns4/localhost/tcp/1234') -// Or a traditional HTTP request -resp = await node.services.http.fetch('multiaddr:/dns4/example.com/tcp/443/tls/http') -// And of course, you can use the fetch API as you normally would -resp = await node.services.http.fetch('https://example.com') - -// This gives you the accessibility of the fetch API with the flexibility of using a p2p network. -``` +This module allows you to use HTTP requests as a transport for libp2p +protocols (libp2p over HTTP), and also libp2p streams as a transport for HTTP +requests (HTTP over libp2p). + +It integrates with existing Node.js friendly HTTP frameworks such as +[express](https://expressjs.com/) and [Fastify](https://fastify.dev) as well +as [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)/ +[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)-based +frameworks like [Hono](https://hono.dev/). + +It even allows creating Node.js-style [http.Server](https://nodejs.org/api/http.html#class-httpserver)s +and [WebSocketServer](https://github.com/websockets/ws/blob/HEAD/doc/ws.md#class-websocketserver)s +in browsers to truly realize the power of the distributed web. + +In addition to URL-based addressing, it can use a libp2p PeerId and/or +multiaddr(s) and lets libp2p take care of the routing, thus taking advantage +of features like multi-routes, NAT traversal and stream multiplexing over a +single connection. + +# Packages + +- [`examples/express-server-over-libp2p`](https://github.com/libp2p/js-libp2p-http/tree/main/examples/express-server-over-libp2p) How to serve an express app over libp2p streams +- [`examples/hono-server-over-libp2p`](https://github.com/libp2p/js-libp2p-http/tree/main/examples/hono-server-over-libp2p) undefined +- [`examples/libp2p-as-http-transport`](https://github.com/libp2p/js-libp2p-http/tree/main/examples/libp2p-as-http-transport) undefined +- [`examples/libp2p-over-http-server`](https://github.com/libp2p/js-libp2p-http/tree/main/examples/libp2p-over-http-server) undefined +- [`examples/peer-id-auth`](https://github.com/libp2p/js-libp2p-http/tree/main/examples/peer-id-auth) How to authenticate peers over HTTP +- [`examples/serving-websites-from-web-browsers`](https://github.com/libp2p/js-libp2p-http/tree/main/examples/serving-websites-from-web-browsers) How to serve websites from web browsers using libp2p +- [`examples/websockets-over-libp2p`](https://github.com/libp2p/js-libp2p-http/tree/main/examples/websockets-over-libp2p) How to serve WebSockets over libp2p streams +- [`packages/http`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/http) Accept HTTP requests over libp2p streams or use libp2p protocols over HTTP +- [`packages/http-fetch`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-fetch) libp2p-compatible implementation of the fetch API +- [`packages/http-peer-id-auth`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-peer-id-auth) An implementation of Peer ID Authentication over HTTP +- [`packages/http-ping`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-ping) An HTTP version of the ping protocol +- [`packages/http-server`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-server) HTTP server components +- [`packages/http-utils`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-utils) Shared utils and common code for HTTP modules +- [`packages/http-websocket`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-websocket) libp2p-compatible implementation of the WebSocket API +- [`packages/interop`](https://github.com/libp2p/js-libp2p-http/tree/main/packages/interop) Interop tests for the @libp2p/http collection of modules # Install ```console -$ npm i @libp2p/http-fetch +$ npm i @libp2p/http ``` ## Browser ` + ``` # API Docs -- +- # License Licensed under either of -- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http-fetch/LICENSE-APACHE) / ) -- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http-fetch/LICENSE-MIT) / ) +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/LICENSE-MIT) / ) # Contribution diff --git a/examples/README.md b/examples/README.md index a15a9ef..74b3774 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,8 +1,26 @@ # Examples of using libp2p+http -TODO +## HTTP over libp2p -## two-js-peers -## hono-server-over-libp2p -## go-libp2p-http-proxy -## js-libp2p-client-and-node-server +These examples involve starting a libp2p node and having it provide the +networking layer for a HTTP server. + +With this configuration you can use libp2p for peer routing, NAT traversal and +other features, but define your own web application server in the framework you +are most familiar with. + +- [Express server over libp2p](./express-server-over-libp2p) +- [Hono server over libp2p](./hono-server-over-libp2p) +- [WebSockets over libp2p](./websockets-over-libp2p) +- [libp2p as a HTTP transport]('./libp2p-as-http-transport) + +## libp2p over HTTP + +These examples start a HTTP server and then pass incoming requests to libp2p. + +- [libp2p over http.Server]('./libp2p-over-http-server) + +## Other features + +- [PeerID authentication]('./peer-id-auth) +- [Serving websites from browsers]('./serving-websites-from-browsers) diff --git a/examples/express-server-over-libp2p/README.md b/examples/express-server-over-libp2p/README.md new file mode 100644 index 0000000..27ce2e3 --- /dev/null +++ b/examples/express-server-over-libp2p/README.md @@ -0,0 +1,55 @@ +# Serving an Express app over libp2p + +In this example we will start a libp2p node that listens for incoming streams +that use the `/http/1.1` protocol. + +It will convert the incoming stream to a [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage) +and hand it off to a Node.js [http.Server](https://nodejs.org/api/http.html#class-httpserver), +then write data passed to the corresponding [http.ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse) +back into the stream for the client to read. + +## Step 1 - start the server + +The script at [./src/server.js](./src/server.js) creates a basic [express](https://expressjs.com/) +app that has a simple "Hello world" route mounted on `/`. + +It creates a `http.Server` to pass HTTP requests to the express app, and finally +a libp2p node to make incoming `Stream`s conform to the `net.Socket` API and +pass them to the `http.Server`. + +Run the server with the following command: + +```console +node src/server.js +Server listening on: +/ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +/ip4/192.168.1.226/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +``` + +## Step 2 - run the client + +The script at [./src/client.js](./src/client.js) starts a libp2p node with the +TCP transport, accepts a command line argument of a multiaddr and makes a HTTP +request to it over a libp2p stream. + +Copy one of the multiaddrs the server is listening on and pass it as a CLI arg: + +```console +node ./src/client.js /ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +GET /ip4/127.0.0.1/tcp/55265/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt 200 OK +Hello World! +``` + +## Next steps + +Experiment with the server - can you make it accept requests on other paths? + +What about query parameters or custom headers? + +> [!TIP] +> You can add `http-path` tuples to a multiaddr with: +> ``` +> addr.encapsulate(`/http-path/${encodeURIComponent(foo?bar=baz)}`) +> ``` + +How about making a request with a body such as a `POST` request? diff --git a/examples/express-server-over-libp2p/package.json b/examples/express-server-over-libp2p/package.json new file mode 100644 index 0000000..2e249af --- /dev/null +++ b/examples/express-server-over-libp2p/package.json @@ -0,0 +1,34 @@ +{ + "name": "@libp2p/http-example-express-server-over-libp2p", + "version": "1.0.0", + "description": "How to serve an express app over libp2p streams", + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "project": true, + "sourceType": "module" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "test": "test-node-example test/*" + }, + "dependencies": { + "@chainsafe/libp2p-noise": "^16.1.3", + "@chainsafe/libp2p-yamux": "^7.0.1", + "@libp2p/http": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "@libp2p/tcp": "^10.1.13", + "@multiformats/multiaddr": "^12.4.0", + "express": "^5.1.0", + "libp2p": "^2.8.8" + }, + "devDependencies": { + "aegir": "^47.0.16", + "test-ipfs-example": "^1.3.3" + }, + "private": true, + "type": "module" +} diff --git a/examples/express-server-over-libp2p/src/client.js b/examples/express-server-over-libp2p/src/client.js new file mode 100644 index 0000000..631283b --- /dev/null +++ b/examples/express-server-over-libp2p/src/client.js @@ -0,0 +1,42 @@ +/* eslint-disable no-console */ + +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { tcp } from '@libp2p/tcp' +import { multiaddr } from '@multiformats/multiaddr' +import { createLibp2p } from 'libp2p' + +// Take the first argument as the path of the folder to add +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node client.js ') + process.exit(1) +} + +// turn the passed arg into a multiaddr +const addr = multiaddr(args[0]) + +const node = await createLibp2p({ + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http() + } +}) + +// make a HTTP request over libp2p +const res = await node.services.http.fetch(addr) + +console.info('GET', addr.toString(), res.status, res.statusText) +console.info(await res.text()) diff --git a/examples/express-server-over-libp2p/src/server.js b/examples/express-server-over-libp2p/src/server.js new file mode 100644 index 0000000..d54fa6d --- /dev/null +++ b/examples/express-server-over-libp2p/src/server.js @@ -0,0 +1,54 @@ +/* eslint-disable no-console */ + +import { createServer } from 'node:http' +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { nodeServer } from '@libp2p/http-server' +import { tcp } from '@libp2p/tcp' +import express from 'express' +import { createLibp2p } from 'libp2p' + +// this express app is where any business logic necessary to server HTTP +// resources will take place +const app = express() +app.get('/', (req, res) => { + res.send('Hello World!') +}) + +// this Node.js http.Server will receive incoming socket connections and convert +// them to HTTP requests - note that we don't need to call `server.listen` - +// libp2p will provide the networking layer +const server = createServer() +server.on('request', (req, res) => { + app(req, res) +}) + +// create a libp2p node that listens on a TCP address +const node = await createLibp2p({ + addresses: { + listen: [ + '/ip4/0.0.0.0/tcp/0' + ] + }, + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http({ + // allow injecting requests into the Node.js http.Server + server: nodeServer(server) + }) + } +}) + +console.info('Server listening on:') +node.getMultiaddrs().forEach(ma => { + console.info(ma.toString()) +}) diff --git a/examples/express-server-over-libp2p/test/index.spec.js b/examples/express-server-over-libp2p/test/index.spec.js new file mode 100644 index 0000000..1280ab6 --- /dev/null +++ b/examples/express-server-over-libp2p/test/index.spec.js @@ -0,0 +1,29 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { matchOutput } from 'test-ipfs-example/node' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// Step 1 start server +process.stdout.write('node server.js\n') + +const { + process: server, + matches: addresses +} = await matchOutput(/Server listening on:\n(.*)\n/, 'node', [path.resolve(__dirname, '../src/server.js')]) + +const address = addresses.slice(1).map(line => line.trim()).pop() + +process.stdout.write('==================================================================\n') + +// Step 2 start client +process.stdout.write(`node client.js ${address}\n`) + +const { + process: client +} = await matchOutput(/Hello World!/g, 'node', [path.resolve(__dirname, '../src/client.js'), address]) + +process.stdout.write('==================================================================\n') + +client.kill() +server.kill() diff --git a/examples/go-libp2p-http-proxy/client.js b/examples/go-libp2p-http-proxy/client.js deleted file mode 100644 index 8d25612..0000000 --- a/examples/go-libp2p-http-proxy/client.js +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable no-console */ - -import { noise } from '@chainsafe/libp2p-noise' -import { yamux } from '@chainsafe/libp2p-yamux' -import { http } from '@libp2p/http-fetch' -import { tcp } from '@libp2p/tcp' -import { multiaddr } from '@multiformats/multiaddr' -import { createLibp2p } from 'libp2p' - -const node = await createLibp2p({ - // libp2p nodes are started by default, pass false to override this - start: false, - addresses: { - listen: [] - }, - transports: [tcp()], - connectionEncrypters: [noise()], - streamMuxers: [yamux()], - services: { http: http() } -}) - -// start libp2p -await node.start() -console.error('libp2p has started') - -// Read server multiaddr from the command line -const serverAddr = process.argv[2] -if (!serverAddr) { - console.error('Please provide the server multiaddr as an argument') - process.exit(1) -} - -let serverMA = multiaddr(serverAddr) - -// check if this is an http transport multiaddr -const isHTTPTransport = serverMA.protos().find(p => p.name === 'http') -if (!isHTTPTransport && serverMA.getPeerId() === null) { - // Learn the peer id of the server. This lets us reuse the connection for all our HTTP requests. - // Otherwise js-libp2p will open a new connection for each request. - const conn = await node.dial(serverMA) - serverMA = serverMA.encapsulate(`/p2p/${conn.remotePeer.toString()}`) -} - -console.error(`Making request to ${serverMA.toString()}`) -try { - const resp = await node.services.http.fetch(new Request(`multiaddr:${serverMA}`)) - const respBody = await resp.text() - if (resp.status !== 200) { - throw new Error(`Unexpected status code: ${resp.status}`) - } - if (respBody !== 'Hello, World!') { - throw new Error(`Unexpected response body: ${respBody}`) - } - console.error('Got response:', respBody) -} finally { - // stop libp2p - await node.stop() -} diff --git a/examples/go-libp2p-http-proxy/proxy/go.mod b/examples/go-libp2p-http-proxy/proxy/go.mod deleted file mode 100644 index f840d7a..0000000 --- a/examples/go-libp2p-http-proxy/proxy/go.mod +++ /dev/null @@ -1,114 +0,0 @@ -module github.com/libp2p/js-libp2p-http-fetch/examples/proxy - -go 1.22.1 -toolchain go1.24.1 - -require ( - github.com/libp2p/go-libp2p v0.35.0 - github.com/multiformats/go-multiaddr v0.12.4 -) - -require ( - github.com/benbjohnson/clock v1.3.5 // indirect - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/containerd/cgroups v1.1.0 // indirect - github.com/coreos/go-systemd/v22 v22.5.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c // indirect - github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect - github.com/docker/go-units v0.5.0 // indirect - github.com/elastic/gosigar v0.14.2 // indirect - github.com/flynn/noise v1.1.0 // indirect - github.com/francoispqt/gojay v1.2.13 // indirect - github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect - github.com/godbus/dbus/v5 v5.1.0 // indirect - github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/gopacket v1.1.19 // indirect - github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 // indirect - github.com/google/uuid v1.4.0 // indirect - github.com/gorilla/websocket v1.5.1 // indirect - github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect - github.com/huin/goupnp v1.3.0 // indirect - github.com/ipfs/go-cid v0.4.1 // indirect - github.com/ipfs/go-log/v2 v2.5.1 // indirect - github.com/jackpal/go-nat-pmp v1.0.2 // indirect - github.com/jbenet/go-temp-err-catcher v0.1.0 // indirect - github.com/klauspost/compress v1.17.8 // indirect - github.com/klauspost/cpuid/v2 v2.2.7 // indirect - github.com/koron/go-ssdp v0.0.4 // indirect - github.com/libp2p/go-buffer-pool v0.1.0 // indirect - github.com/libp2p/go-flow-metrics v0.1.0 // indirect - github.com/libp2p/go-libp2p-asn-util v0.4.1 // indirect - github.com/libp2p/go-msgio v0.3.0 // indirect - github.com/libp2p/go-nat v0.2.0 // indirect - github.com/libp2p/go-netroute v0.2.1 // indirect - github.com/libp2p/go-reuseport v0.4.0 // indirect - github.com/libp2p/go-yamux/v4 v4.0.1 // indirect - github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/miekg/dns v1.1.58 // indirect - github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b // indirect - github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc // indirect - github.com/minio/sha256-simd v1.0.1 // indirect - github.com/mr-tron/base58 v1.2.0 // indirect - github.com/multiformats/go-base32 v0.1.0 // indirect - github.com/multiformats/go-base36 v0.2.0 // indirect - github.com/multiformats/go-multiaddr-dns v0.3.1 // indirect - github.com/multiformats/go-multiaddr-fmt v0.1.0 // indirect - github.com/multiformats/go-multibase v0.2.0 // indirect - github.com/multiformats/go-multicodec v0.9.0 // indirect - github.com/multiformats/go-multihash v0.2.3 // indirect - github.com/multiformats/go-multistream v0.5.0 // indirect - github.com/multiformats/go-varint v0.0.7 // indirect - github.com/onsi/ginkgo/v2 v2.15.0 // indirect - github.com/opencontainers/runtime-spec v1.2.0 // indirect - github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 // indirect - github.com/pion/datachannel v1.5.6 // indirect - github.com/pion/dtls/v2 v2.2.11 // indirect - github.com/pion/ice/v2 v2.3.24 // indirect - github.com/pion/interceptor v0.1.29 // indirect - github.com/pion/logging v0.2.2 // indirect - github.com/pion/mdns v0.0.12 // indirect - github.com/pion/randutil v0.1.0 // indirect - github.com/pion/rtcp v1.2.14 // indirect - github.com/pion/rtp v1.8.6 // indirect - github.com/pion/sctp v1.8.16 // indirect - github.com/pion/sdp/v3 v3.0.9 // indirect - github.com/pion/srtp/v2 v2.0.18 // indirect - github.com/pion/stun v0.6.1 // indirect - github.com/pion/transport/v2 v2.2.5 // indirect - github.com/pion/turn/v2 v2.1.6 // indirect - github.com/pion/webrtc/v3 v3.2.40 // indirect - github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect - github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.48.0 // indirect - github.com/prometheus/procfs v0.12.0 // indirect - github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/quic-go v0.44.0 // indirect - github.com/quic-go/webtransport-go v0.8.0 // indirect - github.com/raulk/go-watchdog v1.3.0 // indirect - github.com/spaolacci/murmur3 v1.1.0 // indirect - github.com/stretchr/testify v1.9.0 // indirect - go.uber.org/dig v1.17.1 // indirect - go.uber.org/fx v1.22.0 // indirect - go.uber.org/mock v0.4.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.35.0 // indirect - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/net v0.36.0 // indirect - golang.org/x/sync v0.11.0 // indirect - golang.org/x/sys v0.30.0 // indirect - golang.org/x/text v0.22.0 // indirect - golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect - google.golang.org/protobuf v1.34.1 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.2.1 // indirect -) - -// Get this fix in: https://github.com/libp2p/go-libp2p/pull/2821 -replace github.com/libp2p/go-libp2p => github.com/libp2p/go-libp2p v0.35.1-0.20240605000535-f11a9c3c7cbb diff --git a/examples/go-libp2p-http-proxy/proxy/go.sum b/examples/go-libp2p-http-proxy/proxy/go.sum deleted file mode 100644 index 9efb8bd..0000000 --- a/examples/go-libp2p-http-proxy/proxy/go.sum +++ /dev/null @@ -1,553 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.0/go.mod h1:TS1dMSSfndXH133OKGwekG838Om/cQT0BUHV3HcBgoo= -dmitri.shuralyov.com/app/changes v0.0.0-20180602232624-0a106ad413e3/go.mod h1:Yl+fi1br7+Rr3LqpNJf1/uxUdtRUV+Tnj0o93V2B9MU= -dmitri.shuralyov.com/html/belt v0.0.0-20180602232347-f7d459c86be0/go.mod h1:JLBrvjyP0v+ecvNYvCpyZgu5/xkfAUhi6wJj28eUfSU= -dmitri.shuralyov.com/service/change v0.0.0-20181023043359-a85b471d5412/go.mod h1:a1inKt/atXimZ4Mv927x+r7UpyzRUf4emIoiiSC2TN4= -dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D6DFvNNtx+9ybjezNCa8XF0xaYcETyp6rHWU= -git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/benbjohnson/clock v1.3.5 h1:VvXlSJBzZpA/zum6Sj74hxwYI2DIxRWuNIoXAzHZz5o= -github.com/benbjohnson/clock v1.3.5/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= -github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= -github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/containerd/cgroups v0.0.0-20201119153540-4cbc285b3327/go.mod h1:ZJeTFisyysqgcCdecO57Dj79RfL0LNeGiFUqLYQRYLE= -github.com/containerd/cgroups v1.1.0 h1:v8rEWFl6EoqHB+swVNjVoCJE8o3jX7e8nqBGPLaDFBM= -github.com/containerd/cgroups v1.1.0/go.mod h1:6ppBcbh/NOOUU+dMKrykgaBnK9lCIBxHqJDGwsa1mIw= -github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.1.0/go.mod h1:xO0FLkIi5MaZafQlIrOotqXZ90ih+1atmu1JpKERPPk= -github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs= -github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c h1:pFUpOrbxDR6AkioZ1ySsx5yxlDQZ8stG2b88gTPxgJU= -github.com/davidlazar/go-crypto v0.0.0-20200604182044-b73af7476f6c/go.mod h1:6UhI8N9EjYm1c2odKpFpAYeR8dsBeM7PtzQhRgxRr9U= -github.com/decred/dcrd/crypto/blake256 v1.0.1 h1:7PltbUIQB7u/FfZ39+DGa/ShuMyJ5ilcvdfma9wOH6Y= -github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 h1:rpfIENRNNilwHwZeG5+P150SMrnNEcHYvcCuK6dPZSg= -github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= -github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/elastic/gosigar v0.12.0/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/elastic/gosigar v0.14.2 h1:Dg80n8cr90OZ7x+bAax/QjoW/XqTI11RmA79ZwIm9/4= -github.com/elastic/gosigar v0.14.2/go.mod h1:iXRIGg2tLnu7LBdpqzyQfGDEidKCfWcCMS0WKyPWoMs= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= -github.com/flynn/noise v1.1.0 h1:KjPQoQCEFdZDiP03phOvGi11+SVVhBG2wOWAorLsstg= -github.com/flynn/noise v1.1.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= -github.com/francoispqt/gojay v1.2.13 h1:d2m3sFjloqoIUQU3TsHBgj6qg/BVGlTBeHDUmyJnXKk= -github.com/francoispqt/gojay v1.2.13/go.mod h1:ehT5mTG4ua4581f1++1WLG0vPdaA9HaiDsoyrBGkyDY= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= -github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= -github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= -github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= -github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= -github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= -github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5 h1:E/LAvt58di64hlYjx7AsNS6C/ysHWYo+2qPCZKTQhRo= -github.com/google/pprof v0.0.0-20240207164012-fb44976bdcd5/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik= -github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= -github.com/googleapis/gax-go/v2 v2.0.3/go.mod h1:LLvjysVCY1JZeum8Z6l8qUty8fiNwE08qbEPm1M08qg= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= -github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= -github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= -github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= -github.com/ipfs/go-cid v0.4.1 h1:A/T3qGvxi4kpKWWcPC/PgbvDA2bjVLO7n4UeVwnbs/s= -github.com/ipfs/go-cid v0.4.1/go.mod h1:uQHwDeX4c6CtyrFwdqyhpNcxVewur1M7l7fNU7LKwZk= -github.com/ipfs/go-log/v2 v2.5.1 h1:1XdUzF7048prq4aBjDQQ4SL5RxftpRGdXhNRwKSAlcY= -github.com/ipfs/go-log/v2 v2.5.1/go.mod h1:prSpmC1Gpllc9UYWxDiZDreBYw7zp4Iqp1kOLU9U5UI= -github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= -github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= -github.com/jbenet/go-temp-err-catcher v0.1.0 h1:zpb3ZH6wIE8Shj2sKS+khgRvf7T7RABoLk/+KKHggpk= -github.com/jbenet/go-temp-err-catcher v0.1.0/go.mod h1:0kJRvmDZXNMIiJirNPEYfhpPwbGVtZVWC34vc5WLsDk= -github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= -github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= -github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= -github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= -github.com/koron/go-ssdp v0.0.4 h1:1IDwrghSKYM7yLf7XCzbByg2sJ/JcNOZRXS2jczTwz0= -github.com/koron/go-ssdp v0.0.4/go.mod h1:oDXq+E5IL5q0U8uSBcoAXzTzInwy5lEgC91HoKtbmZk= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/libp2p/go-buffer-pool v0.1.0 h1:oK4mSFcQz7cTQIfqbe4MIj9gLW+mnanjyFtc6cdF0Y8= -github.com/libp2p/go-buffer-pool v0.1.0/go.mod h1:N+vh8gMqimBzdKkSMVuydVDq+UV5QTWy5HSiZacSbPg= -github.com/libp2p/go-flow-metrics v0.1.0 h1:0iPhMI8PskQwzh57jB9WxIuIOQ0r+15PChFGkx3Q3WM= -github.com/libp2p/go-flow-metrics v0.1.0/go.mod h1:4Xi8MX8wj5aWNDAZttg6UPmc0ZrnFNsMtpsYUClFtro= -github.com/libp2p/go-libp2p v0.35.1-0.20240605000535-f11a9c3c7cbb h1:jpsKowOxM3bJACYYiP3J8S5Ls+3B/V6uGedmjmxkbNU= -github.com/libp2p/go-libp2p v0.35.1-0.20240605000535-f11a9c3c7cbb/go.mod h1:yvTaBR9foLKTyfJlpEtHu5SNtyHnw15i7/mQqTSa4dY= -github.com/libp2p/go-libp2p-asn-util v0.4.1 h1:xqL7++IKD9TBFMgnLPZR6/6iYhawHKHl950SO9L6n94= -github.com/libp2p/go-libp2p-asn-util v0.4.1/go.mod h1:d/NI6XZ9qxw67b4e+NgpQexCIiFYJjErASrYW4PFDN8= -github.com/libp2p/go-libp2p-testing v0.12.0 h1:EPvBb4kKMWO29qP4mZGyhVzUyR25dvfUIK5WDu6iPUA= -github.com/libp2p/go-libp2p-testing v0.12.0/go.mod h1:KcGDRXyN7sQCllucn1cOOS+Dmm7ujhfEyXQL5lvkcPg= -github.com/libp2p/go-msgio v0.3.0 h1:mf3Z8B1xcFN314sWX+2vOTShIE0Mmn2TXn3YCUQGNj0= -github.com/libp2p/go-msgio v0.3.0/go.mod h1:nyRM819GmVaF9LX3l03RMh10QdOroF++NBbxAb0mmDM= -github.com/libp2p/go-nat v0.2.0 h1:Tyz+bUFAYqGyJ/ppPPymMGbIgNRH+WqC5QrT5fKrrGk= -github.com/libp2p/go-nat v0.2.0/go.mod h1:3MJr+GRpRkyT65EpVPBstXLvOlAPzUVlG6Pwg9ohLJk= -github.com/libp2p/go-netroute v0.2.1 h1:V8kVrpD8GK0Riv15/7VN6RbUQ3URNZVosw7H2v9tksU= -github.com/libp2p/go-netroute v0.2.1/go.mod h1:hraioZr0fhBjG0ZRXJJ6Zj2IVEVNx6tDTFQfSmcq7mQ= -github.com/libp2p/go-reuseport v0.4.0 h1:nR5KU7hD0WxXCJbmw7r2rhRYruNRl2koHw8fQscQm2s= -github.com/libp2p/go-reuseport v0.4.0/go.mod h1:ZtI03j/wO5hZVDFo2jKywN6bYKWLOy8Se6DrI2E1cLU= -github.com/libp2p/go-yamux/v4 v4.0.1 h1:FfDR4S1wj6Bw2Pqbc8Uz7pCxeRBPbwsBbEdfwiCypkQ= -github.com/libp2p/go-yamux/v4 v4.0.1/go.mod h1:NWjl8ZTLOGlozrXSOZ/HlfG++39iKNnM5wwmtQP1YB4= -github.com/lunixbochs/vtclean v1.0.0/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI= -github.com/mailru/easyjson v0.0.0-20190312143242-1de009706dbe/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd h1:br0buuQ854V8u83wA0rVZ8ttrq5CpaPZdvrK0LP2lOk= -github.com/marten-seemann/tcp v0.0.0-20210406111302-dfbc87cc63fd/go.mod h1:QuCEs1Nt24+FYQEqAAncTDPJIuGs+LxK1MCiFL25pMU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= -github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= -github.com/miekg/dns v1.1.58 h1:ca2Hdkz+cDg/7eNF6V56jjzuZ4aCAE+DbVkILdQWG/4= -github.com/miekg/dns v1.1.58/go.mod h1:Ypv+3b/KadlvW9vJfXOTf300O4UqaHFzFCuHz+rPkBY= -github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c h1:bzE/A84HN25pxAuk9Eej1Kz9OUelF97nAc82bDquQI8= -github.com/mikioh/tcp v0.0.0-20190314235350-803a9b46060c/go.mod h1:0SQS9kMwD2VsyFEB++InYyBJroV/FRmBgcydeSUcJms= -github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b h1:z78hV3sbSMAUoyUMM0I83AUIT6Hu17AWfgjzIbtrYFc= -github.com/mikioh/tcpinfo v0.0.0-20190314235526-30a79bb1804b/go.mod h1:lxPUiZwKoFL8DUUmalo2yJJUCxbPKtm8OKfqr2/FTNU= -github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc h1:PTfri+PuQmWDqERdnNMiD9ZejrlswWrCpBEZgWOiTrc= -github.com/mikioh/tcpopt v0.0.0-20190314235656-172688c1accc/go.mod h1:cGKTAVKx4SxOuR/czcZ/E2RSJ3sfHs8FpHhQ5CWMf9s= -github.com/minio/blake2b-simd v0.0.0-20160723061019-3f5f724cb5b1/go.mod h1:pD8RvIylQ358TN4wwqatJ8rNavkEINozVn9DtGI3dfQ= -github.com/minio/sha256-simd v0.1.1-0.20190913151208-6de447530771/go.mod h1:B5e1o+1/KgNmWrSQK08Y6Z1Vb5pwIktudl0J58iy0KM= -github.com/minio/sha256-simd v1.0.1 h1:6kaan5IFmwTNynnKKpDHe6FWHohJOHhCPchzK49dzMM= -github.com/minio/sha256-simd v1.0.1/go.mod h1:Pz6AKMiUdngCLpeTL/RJY1M9rUuPMYujV5xJjtbRSN8= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= -github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= -github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= -github.com/multiformats/go-base32 v0.1.0/go.mod h1:Kj3tFY6zNr+ABYMqeUNeGvkIC/UYgtWibDcT0rExnbI= -github.com/multiformats/go-base36 v0.2.0 h1:lFsAbNOGeKtuKozrtBsAkSVhv1p9D0/qedU9rQyccr0= -github.com/multiformats/go-base36 v0.2.0/go.mod h1:qvnKE++v+2MWCfePClUEjE78Z7P2a1UV0xHgWc0hkp4= -github.com/multiformats/go-multiaddr v0.1.1/go.mod h1:aMKBKNEYmzmDmxfX88/vz+J5IU55txyt0p4aiWVohjo= -github.com/multiformats/go-multiaddr v0.2.0/go.mod h1:0nO36NvPpyV4QzvTLi/lafl2y95ncPj0vFwVF6k6wJ4= -github.com/multiformats/go-multiaddr v0.12.4 h1:rrKqpY9h+n80EwhhC/kkcunCZZ7URIF8yN1WEUt2Hvc= -github.com/multiformats/go-multiaddr v0.12.4/go.mod h1:sBXrNzucqkFJhvKOiwwLyqamGa/P5EIXNPLovyhQCII= -github.com/multiformats/go-multiaddr-dns v0.3.1 h1:QgQgR+LQVt3NPTjbrLLpsaT2ufAA2y0Mkk+QRVJbW3A= -github.com/multiformats/go-multiaddr-dns v0.3.1/go.mod h1:G/245BRQ6FJGmryJCrOuTdB37AMA5AMOVuO6NY3JwTk= -github.com/multiformats/go-multiaddr-fmt v0.1.0 h1:WLEFClPycPkp4fnIzoFoV9FVd49/eQsuaL3/CWe167E= -github.com/multiformats/go-multiaddr-fmt v0.1.0/go.mod h1:hGtDIW4PU4BqJ50gW2quDuPVjyWNZxToGUh/HwTZYJo= -github.com/multiformats/go-multibase v0.2.0 h1:isdYCVLvksgWlMW9OZRYJEa9pZETFivncJHmHnnd87g= -github.com/multiformats/go-multibase v0.2.0/go.mod h1:bFBZX4lKCA/2lyOFSAoKH5SS6oPyjtnzK/XTFDPkNuk= -github.com/multiformats/go-multicodec v0.9.0 h1:pb/dlPnzee/Sxv/j4PmkDRxCOi3hXTz3IbPKOXWJkmg= -github.com/multiformats/go-multicodec v0.9.0/go.mod h1:L3QTQvMIaVBkXOXXtVmYE+LI16i14xuaojr/H7Ai54k= -github.com/multiformats/go-multihash v0.0.8/go.mod h1:YSLudS+Pi8NHE7o6tb3D8vrpKa63epEDmG8nTduyAew= -github.com/multiformats/go-multihash v0.2.3 h1:7Lyc8XfX/IY2jWb/gI7JP+o7JEq9hOa7BFvVU9RSh+U= -github.com/multiformats/go-multihash v0.2.3/go.mod h1:dXgKXCXjBzdscBLk9JkjINiEsCKRVch90MdaGiKsvSM= -github.com/multiformats/go-multistream v0.5.0 h1:5htLSLl7lvJk3xx3qT/8Zm9J4K8vEOf/QGkvOGQAyiE= -github.com/multiformats/go-multistream v0.5.0/go.mod h1:n6tMZiwiP2wUsR8DgfDWw1dydlEqV3l6N3/GBsX6ILA= -github.com/multiformats/go-varint v0.0.1/go.mod h1:3Ls8CIEsrijN6+B7PbrXRPxHRPuXSrVKRY101jdMZYE= -github.com/multiformats/go-varint v0.0.7 h1:sWSGR+f/eu5ABZA2ZpYKBILXTTs9JWpdEM/nEGOHFS8= -github.com/multiformats/go-varint v0.0.7/go.mod h1:r8PUYw/fD/SjBCiKOoDlGF6QawOELpZAu9eioSos/OU= -github.com/neelance/astrewrite v0.0.0-20160511093645-99348263ae86/go.mod h1:kHJEU3ofeGjhHklVoIGuVj85JJwZ6kWPaJwCIxgnFmo= -github.com/neelance/sourcemap v0.0.0-20151028013722-8c68805598ab/go.mod h1:Qr6/a/Q4r9LP1IltGz7tA7iOK1WonHEYhu1HRBA7ZiM= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= -github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8= -github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ= -github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= -github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58 h1:onHthvaw9LFnH4t2DcNVpwGmV9E1BkGknEliJkfwQj0= -github.com/pbnjay/memory v0.0.0-20210728143218-7b4eea64cf58/go.mod h1:DXv8WO4yhMYhSNPKjeNKa5WY9YCIEBRbNzFFPJbWO6Y= -github.com/pion/datachannel v1.5.6 h1:1IxKJntfSlYkpUj8LlYRSWpYiTTC02nUrOE8T3DqGeg= -github.com/pion/datachannel v1.5.6/go.mod h1:1eKT6Q85pRnr2mHiWHxJwO50SfZRtWHTsNIVb/NfGW4= -github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= -github.com/pion/dtls/v2 v2.2.11 h1:9U/dpCYl1ySttROPWJgqWKEylUdT0fXp/xst6JwY5Ks= -github.com/pion/dtls/v2 v2.2.11/go.mod h1:d9SYc9fch0CqK90mRk1dC7AkzzpwJj6u2GU3u+9pqFE= -github.com/pion/ice/v2 v2.3.24 h1:RYgzhH/u5lH0XO+ABatVKCtRd+4U1GEaCXSMjNr13tI= -github.com/pion/ice/v2 v2.3.24/go.mod h1:KXJJcZK7E8WzrBEYnV4UtqEZsGeWfHxsNqhVcVvgjxw= -github.com/pion/interceptor v0.1.29 h1:39fsnlP1U8gw2JzOFWdfCU82vHvhW9o0rZnZF56wF+M= -github.com/pion/interceptor v0.1.29/go.mod h1:ri+LGNjRUc5xUNtDEPzfdkmSqISixVTBF/z/Zms/6T4= -github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= -github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= -github.com/pion/mdns v0.0.12 h1:CiMYlY+O0azojWDmxdNr7ADGrnZ+V6Ilfner+6mSVK8= -github.com/pion/mdns v0.0.12/go.mod h1:VExJjv8to/6Wqm1FXK+Ii/Z9tsVk/F5sD/N70cnYFbk= -github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA= -github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8= -github.com/pion/rtcp v1.2.12/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtcp v1.2.14 h1:KCkGV3vJ+4DAJmvP0vaQShsb0xkRfWkO540Gy102KyE= -github.com/pion/rtcp v1.2.14/go.mod h1:sn6qjxvnwyAkkPzPULIbVqSKI5Dv54Rv7VG0kNxh9L4= -github.com/pion/rtp v1.8.3/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/rtp v1.8.6 h1:MTmn/b0aWWsAzux2AmP8WGllusBVw4NPYPVFFd7jUPw= -github.com/pion/rtp v1.8.6/go.mod h1:pBGHaFt/yW7bf1jjWAoUjpSNoDnw98KTMg+jWWvziqU= -github.com/pion/sctp v1.8.13/go.mod h1:YKSgO/bO/6aOMP9LCie1DuD7m+GamiK2yIiPM6vH+GA= -github.com/pion/sctp v1.8.16 h1:PKrMs+o9EMLRvFfXq59WFsC+V8mN1wnKzqrv+3D/gYY= -github.com/pion/sctp v1.8.16/go.mod h1:P6PbDVA++OJMrVNg2AL3XtYHV4uD6dvfyOovCgMs0PE= -github.com/pion/sdp/v3 v3.0.9 h1:pX++dCHoHUwq43kuwf3PyJfHlwIj4hXA7Vrifiq0IJY= -github.com/pion/sdp/v3 v3.0.9/go.mod h1:B5xmvENq5IXJimIO4zfp6LAe1fD9N+kFv+V/1lOdz8M= -github.com/pion/srtp/v2 v2.0.18 h1:vKpAXfawO9RtTRKZJbG4y0v1b11NZxQnxRl85kGuUlo= -github.com/pion/srtp/v2 v2.0.18/go.mod h1:0KJQjA99A6/a0DOVTu1PhDSw0CXF2jTkqOoMg3ODqdA= -github.com/pion/stun v0.6.1 h1:8lp6YejULeHBF8NmV8e2787BogQhduZugh5PdhDyyN4= -github.com/pion/stun v0.6.1/go.mod h1:/hO7APkX4hZKu/D0f2lHzNyvdkTGtIy3NDmLR7kSz/8= -github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= -github.com/pion/transport/v2 v2.2.2/go.mod h1:OJg3ojoBJopjEeECq2yJdXH9YVrUJ1uQ++NjXLOUorc= -github.com/pion/transport/v2 v2.2.3/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v2 v2.2.4/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v2 v2.2.5 h1:iyi25i/21gQck4hfRhomF6SktmUQjRsRW4WJdhfc3Kc= -github.com/pion/transport/v2 v2.2.5/go.mod h1:q2U/tf9FEfnSBGSW6w5Qp5PFWRLRj3NjLhCCgpRK4p0= -github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= -github.com/pion/transport/v3 v3.0.2 h1:r+40RJR25S9w3jbA6/5uEPTzcdn7ncyU44RWCbHkLg4= -github.com/pion/transport/v3 v3.0.2/go.mod h1:nIToODoOlb5If2jF9y2Igfx3PFYWfuXi37m0IlWa/D0= -github.com/pion/turn/v2 v2.1.3/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/turn/v2 v2.1.6 h1:Xr2niVsiPTB0FPtt+yAWKFUkU1eotQbGgpTIld4x1Gc= -github.com/pion/turn/v2 v2.1.6/go.mod h1:huEpByKKHix2/b9kmTAM3YoX6MKP+/D//0ClgUYR2fY= -github.com/pion/webrtc/v3 v3.2.40 h1:Wtfi6AZMQg+624cvCXUuSmrKWepSB7zfgYDOYqsSOVU= -github.com/pion/webrtc/v3 v3.2.40/go.mod h1:M1RAe3TNTD1tzyvqHrbVODfwdPGSXOUo/OgpoGGJqFY= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= -github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= -github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= -github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= -github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= -github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= -github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/quic-go v0.44.0 h1:So5wOr7jyO4vzL2sd8/pD9Kesciv91zSk8BoFngItQ0= -github.com/quic-go/quic-go v0.44.0/go.mod h1:z4cx/9Ny9UtGITIPzmPTXh1ULfOyWh4qGQlpnPcWmek= -github.com/quic-go/webtransport-go v0.8.0 h1:HxSrwun11U+LlmwpgM1kEqIqH90IT4N8auv/cD7QFJg= -github.com/quic-go/webtransport-go v0.8.0/go.mod h1:N99tjprW432Ut5ONql/aUhSLT0YVSlwHohQsuac9WaM= -github.com/raulk/go-watchdog v1.3.0 h1:oUmdlHxdkXRJlwfG0O9omj8ukerm8MEQavSiDTEtBsk= -github.com/raulk/go-watchdog v1.3.0/go.mod h1:fIvOnLbF0b0ZwkB9YU4mOW9Did//4vPZtDqv66NfsMU= -github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= -github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= -github.com/shurcooL/github_flavored_markdown v0.0.0-20181002035957-2122de532470/go.mod h1:2dOwnU2uBioM+SGy2aZoq1f/Sd1l9OkAeAUvjSyvgU0= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/gofontwoff v0.0.0-20180329035133-29b52fc0a18d/go.mod h1:05UtEgK5zq39gLST6uB0cf3NEHjETfB4Fgr3Gx5R9Vw= -github.com/shurcooL/gopherjslib v0.0.0-20160914041154-feb6d3990c2c/go.mod h1:8d3azKNyqcHP1GaQE/c6dDgjkgSx2BZ4IoEi4F1reUI= -github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= -github.com/shurcooL/highlight_go v0.0.0-20181028180052-98c3abbbae20/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= -github.com/shurcooL/home v0.0.0-20181020052607-80b7ffcb30f9/go.mod h1:+rgNQw2P9ARFAs37qieuu7ohDNQ3gds9msbT2yn85sg= -github.com/shurcooL/htmlg v0.0.0-20170918183704-d01228ac9e50/go.mod h1:zPn1wHpTIePGnXSHpsVPWEktKXHr6+SS6x/IKRb7cpw= -github.com/shurcooL/httperror v0.0.0-20170206035902-86b7830d14cc/go.mod h1:aYMfkZ6DWSJPJ6c4Wwz3QtW22G7mf/PEgaB9k/ik5+Y= -github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg= -github.com/shurcooL/httpgzip v0.0.0-20180522190206-b1c53ac65af9/go.mod h1:919LwcH0M7/W4fcZ0/jy0qGght1GIhqyS/EgWGH2j5Q= -github.com/shurcooL/issues v0.0.0-20181008053335-6292fdc1e191/go.mod h1:e2qWDig5bLteJ4fwvDAc2NHzqFEthkqn7aOZAOpj+PQ= -github.com/shurcooL/issuesapp v0.0.0-20180602232740-048589ce2241/go.mod h1:NPpHK2TI7iSaM0buivtFUc9offApnI0Alt/K8hcHy0I= -github.com/shurcooL/notifications v0.0.0-20181007000457-627ab5aea122/go.mod h1:b5uSkrEVM1jQUspwbixRBhaIjIzL2xazXp6kntxYle0= -github.com/shurcooL/octicon v0.0.0-20181028054416-fa4f57f9efb2/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= -github.com/shurcooL/reactions v0.0.0-20181006231557-f2e0b4ca5b82/go.mod h1:TCR1lToEk4d2s07G3XGfz2QrgHXg4RJBvjrOozvoWfk= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/users v0.0.0-20180125191416-49c67e49c537/go.mod h1:QJTqeLYEDaXHZDBsXlPCDqdhQuJkuw4NOtaxYe3xii4= -github.com/shurcooL/webdavfs v0.0.0-20170829043945-18c3829fa133/go.mod h1:hKmq5kWdCj2z2KEozexVbfEZIWiTjhE0+UjmZgPqehw= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= -github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= -github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= -github.com/viant/assertly v0.4.8/go.mod h1:aGifi++jvCrUaklKEKT0BU95igDNaqkvz+49uaYMPRU= -github.com/viant/toolbox v0.24.0/go.mod h1:OxMCG57V0PXuIP2HNQrtJf2CjqdmbrOx5EkMILuUhzM= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/dig v1.17.1 h1:Tga8Lz8PcYNsWsyHMZ1Vm0OQOUaJNDyvPImgbAu9YSc= -go.uber.org/dig v1.17.1/go.mod h1:Us0rSJiThwCv2GteUN0Q7OKvU7n5J4dxZ9JKUXozFdE= -go.uber.org/fx v1.22.0 h1:pApUK7yL0OUHMd8vkunWSlLxZVFFk70jR2nKde8X2NM= -go.uber.org/fx v1.22.0/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= -go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI= -go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= -go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= -golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+MfF/py+xQ/tYqIWW03b70/CG9Rw= -golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200602180216-279210d13fed/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs= -golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= -golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= -golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA= -golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= -golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.0.0-20180810173357-98c5dad5d1a0/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o= -golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= -golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= -golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= -golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= -golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= -google.golang.org/api v0.1.0/go.mod h1:UGEZY7KEX120AnNLIHFMKIo4obdJhkp2tPbaPlQx13Y= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20181202183823-bd91e49a0898/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= -google.golang.org/genproto v0.0.0-20190306203927-b5d61aea6440/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= -lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= -sourcegraph.com/sourcegraph/go-diff v0.5.0/go.mod h1:kuch7UrkMzY0X+p9CRK03kfuPQ2zzQcaEFbx8wA8rck= -sourcegraph.com/sqs/pbtypes v0.0.0-20180604144634-d3ebe8f20ae4/go.mod h1:ketZ/q3QxT9HOBeFhu6RdvsftgpsbFHBF5Cas6cDKZ0= diff --git a/examples/go-libp2p-http-proxy/proxy/main.go b/examples/go-libp2p-http-proxy/proxy/main.go deleted file mode 100644 index b88b88a..0000000 --- a/examples/go-libp2p-http-proxy/proxy/main.go +++ /dev/null @@ -1,55 +0,0 @@ -package main - -import ( - "flag" - "fmt" - "log" - "net/http/httputil" - "net/url" - "os" - "os/signal" - - "github.com/libp2p/go-libp2p" - libp2phttp "github.com/libp2p/go-libp2p/p2p/http" - "github.com/multiformats/go-multiaddr" -) - -func main() { - proxyTarget := flag.String("proxy-target", "", "target http server to proxy to") - flag.Parse() - if *proxyTarget == "" { - log.Fatal("proxy-target must be set") - } - - h, err := libp2p.New(libp2p.ListenAddrStrings( - "/ip4/127.0.0.1/tcp/0", - )) - if err != nil { - log.Fatal(err) - } - defer h.Close() - - log.Println("Listening on:") - for _, a := range h.Addrs() { - fmt.Println(a.Encapsulate(multiaddr.StringCast("/p2p/" + h.ID().String()))) - } - - targetUrl, err := url.Parse(*proxyTarget) - if err != nil { - log.Fatal(err) - } - - // reverse proxy - proxy := httputil.NewSingleHostReverseProxy(targetUrl) - - httpHost := libp2phttp.Host{StreamHost: h} - - httpHost.SetHTTPHandlerAtPath("/http-proxy/0.0.1", "/", proxy) - go httpHost.Serve() - - // Wait for interrupt signal to stop - intSig := make(chan os.Signal, 1) - signal.Notify(intSig, os.Interrupt) - <-intSig - log.Println("Interrupt signal received, closing host") -} diff --git a/examples/go-libp2p-http-proxy/proxy/proxy b/examples/go-libp2p-http-proxy/proxy/proxy deleted file mode 100755 index ecb4627..0000000 Binary files a/examples/go-libp2p-http-proxy/proxy/proxy and /dev/null differ diff --git a/examples/go-libp2p-http-proxy/server.js b/examples/go-libp2p-http-proxy/server.js deleted file mode 100644 index 2f6b1f4..0000000 --- a/examples/go-libp2p-http-proxy/server.js +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable no-console */ - -import http from 'http' - -const port = 55776 - -const server = http.createServer((req, res) => { - res.writeHead(200, { 'Content-Type': 'text/plain' }) - res.end('Hello, World!') -}) - -server.listen(port, () => { - console.error(`Server running at: http://localhost:${port}/`) - // Print multiaddr on stdout for test - console.error("Server's multiaddr is:") - console.log(`/dns4/localhost/tcp/${port}/http`) - console.log('') // Empty line to signal we have no more addresses (for test runner) -}) diff --git a/examples/hono-server-over-libp2p/README.md b/examples/hono-server-over-libp2p/README.md new file mode 100644 index 0000000..fda7812 --- /dev/null +++ b/examples/hono-server-over-libp2p/README.md @@ -0,0 +1,54 @@ +# Serving a Hono app over libp2p + +In this example we will start a libp2p node that listens for incoming streams +that use the `/http/1.1` protocol. + +It will convert the incoming stream to a [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) +and hand it off to a fetch-based handler (in the example we use [Hono]()https://hono.dev/) +and then write the returned [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) +back into the stream for the client to read. + +## Step 1 - start the server + +The script at [./src/server.js](./src/server.js) creates a basic [express](https://expressjs.com/) +app that has a simple "Hello world" route mounted on `/`. + +It creates a `Hono` app to serve HTTP content, and a libp2p node to make +incoming `Stream`s conform to the `Request` API and pass them to the app. + +Run the server with the following command: + +```console +node src/server.js +Server listening on: +/ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +/ip4/192.168.1.226/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +``` + +## Step 2 - run the client + +The script at [./src/client.js](./src/client.js) starts a libp2p node with the +TCP transport, accepts a command line argument of a multiaddr and makes a HTTP +request to it over a libp2p stream. + +Copy one of the multiaddrs the server is listening on and pass it as a CLI arg: + +```console +node ./src/client.js /ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +GET /ip4/127.0.0.1/tcp/55265/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt 200 OK +Hello World! +``` + +## Next steps + +Experiment with the server - can you make it accept requests on other paths? + +What about query parameters or custom headers? + +> [!TIP] +> You can add `http-path` tuples to a multiaddr with: +> ``` +> addr.encapsulate(`/http-path/${encodeURIComponent(foo?bar=baz)}`) +> ``` + +How about making a request with a body such as a `POST` request? diff --git a/examples/hono-server-over-libp2p/client.js b/examples/hono-server-over-libp2p/client.js deleted file mode 100644 index 91dd32a..0000000 --- a/examples/hono-server-over-libp2p/client.js +++ /dev/null @@ -1,61 +0,0 @@ -/* eslint-disable no-console */ - -import { noise } from '@chainsafe/libp2p-noise' -import { yamux } from '@chainsafe/libp2p-yamux' -import { http } from '@libp2p/http-fetch' -import { sendPing } from '@libp2p/http-fetch/ping' -import { tcp } from '@libp2p/tcp' -import { multiaddr } from '@multiformats/multiaddr' -import { createLibp2p } from 'libp2p' - -const node = await createLibp2p({ - // libp2p nodes are started by default, pass false to override this - start: false, - addresses: { - listen: [] - }, - transports: [tcp()], - connectionEncrypters: [noise()], - streamMuxers: [yamux()], - services: { http: http() } -}) - -// start libp2p -await node.start() -console.error('libp2p has started') - -// Read server multiaddr from the command line -const serverAddr = process.argv[2] -if (!serverAddr) { - console.error('Please provide the server multiaddr as an argument') - process.exit(1) -} - -let serverMA = multiaddr(serverAddr) - -const isHTTPTransport = serverMA.protos().find(p => p.name === 'http') // check if this is an http transport multiaddr -if (!isHTTPTransport && serverMA.getPeerId() === null) { - // Learn the peer id of the server. This lets us reuse the connection for all our HTTP requests. - // Otherwise js-libp2p will open a new connection for each request. - const conn = await node.dial(serverMA) - serverMA = serverMA.encapsulate(`/p2p/${conn.remotePeer.toString()}`) -} - -console.error('Making request to', `${serverMA.toString()}`) -try { - const resp = await node.services.http.fetch(new Request(`multiaddr:${serverMA}` + `/http-path/${encodeURIComponent('my-app')}`)) - const respBody = await resp.text() - if (resp.status !== 200) { - throw new Error(`Unexpected status code: ${resp.status}`) - } - if (respBody !== 'Hono!') { - throw new Error(`Unexpected response body: ${respBody}`) - } - - const start = new Date().getTime() - await sendPing(node, serverMA) - const end = new Date().getTime() - console.error('HTTP Ping took', end - start, 'ms') -} finally { - await node.stop() -} diff --git a/examples/hono-server-over-libp2p/package.json b/examples/hono-server-over-libp2p/package.json new file mode 100644 index 0000000..df9996c --- /dev/null +++ b/examples/hono-server-over-libp2p/package.json @@ -0,0 +1,33 @@ +{ + "name": "@libp2p/http-example-hono-server-over-libp2p", + "version": "1.0.0", + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "project": true, + "sourceType": "module" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "test": "test-node-example test/*" + }, + "dependencies": { + "@chainsafe/libp2p-noise": "^16.1.3", + "@chainsafe/libp2p-yamux": "^7.0.1", + "@libp2p/http": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "@libp2p/tcp": "^10.1.13", + "@multiformats/multiaddr": "^12.4.0", + "hono": "^4.7.10", + "libp2p": "^2.8.8" + }, + "devDependencies": { + "aegir": "^47.0.16", + "test-ipfs-example": "^1.3.3" + }, + "private": true, + "type": "module" +} diff --git a/examples/hono-server-over-libp2p/server.js b/examples/hono-server-over-libp2p/server.js deleted file mode 100644 index d302ba4..0000000 --- a/examples/hono-server-over-libp2p/server.js +++ /dev/null @@ -1,65 +0,0 @@ -/* eslint-disable no-console */ - -import { noise } from '@chainsafe/libp2p-noise' -import { yamux } from '@chainsafe/libp2p-yamux' -import { serve } from '@hono/node-server' -import { WELL_KNOWN_PROTOCOLS, httpCustomServer } from '@libp2p/http-fetch' -import { PING_PROTOCOL_ID, servePing } from '@libp2p/http-fetch/ping' -import { tcp } from '@libp2p/tcp' -import { Hono } from 'hono' -import { createLibp2p } from 'libp2p' - -const app = new Hono() - -const node = await createLibp2p({ - // libp2p nodes are started by default, pass false to override this - start: false, - addresses: { - listen: ['/ip4/127.0.0.1/tcp/8000'] - }, - transports: [tcp()], - connectionEncrypters: [noise()], - streamMuxers: [yamux()], - services: { http: httpCustomServer({ customHTTPHandler: app.fetch.bind(app) }) } -}) - -app.get(WELL_KNOWN_PROTOCOLS, async (c) => { - return node.services.http.serveWellKnownProtocols(c.req) -}) -app.get('/my-app', (c) => c.text('Hono!')) -node.services.http.registerProtocol('/example-app/0.0.1', '/my-app') - -// Register HTTP ping protocol -app.all('/ping', (c) => { - return servePing(c.req) -}) -node.services.http.registerProtocol(PING_PROTOCOL_ID, '/ping') - -// start libp2p -await node.start() -console.error('libp2p has started') - -// Also listen on a standard http transport -const server = serve({ - fetch: app.fetch, - port: 8001, - hostname: '127.0.0.1' -}) - -const listenAddrs = node.getMultiaddrs() -console.error('libp2p is listening on the following addresses:') -console.log('/ip4/127.0.0.1/tcp/8001/http') -for (const addr of listenAddrs) { - console.log(addr.toString()) -} -console.log('') // Empty line to signal we have no more addresses (for test runner) - -// wait for SIGINT -await new Promise(resolve => process.on('SIGINT', resolve)) - -// Stop the http server -server.close() - -// stop libp2p -node.stop() -console.error('libp2p has stopped') diff --git a/examples/hono-server-over-libp2p/src/client.js b/examples/hono-server-over-libp2p/src/client.js new file mode 100644 index 0000000..f27fabc --- /dev/null +++ b/examples/hono-server-over-libp2p/src/client.js @@ -0,0 +1,41 @@ +/* eslint-disable no-console */ + +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { tcp } from '@libp2p/tcp' +import { multiaddr } from '@multiformats/multiaddr' +import { createLibp2p } from 'libp2p' + +// Take the first argument as the path of the folder to add +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node client.js ') +} + +// turn the passed arg into a multiaddr +const addr = multiaddr(args[0]) + +const node = await createLibp2p({ + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http() + } +}) + +// make a HTTP request over libp2p +const res = await node.services.http.fetch(addr) + +console.info('GET', addr.toString(), res.status, res.statusText) +console.info(await res.text()) diff --git a/examples/hono-server-over-libp2p/src/server.js b/examples/hono-server-over-libp2p/src/server.js new file mode 100644 index 0000000..b0e2606 --- /dev/null +++ b/examples/hono-server-over-libp2p/src/server.js @@ -0,0 +1,45 @@ +/* eslint-disable no-console */ + +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { fetchServer } from '@libp2p/http-server' +import { tcp } from '@libp2p/tcp' +import { Hono } from 'hono' +import { createLibp2p } from 'libp2p' + +// this Hono app is where any business logic necessary to server HTTP +// resources will take place +const app = new Hono() +app.get('/', (c) => { + return c.text('Hello World!') +}) + +// create a libp2p node that listens on a TCP address +const node = await createLibp2p({ + addresses: { + listen: [ + '/ip4/0.0.0.0/tcp/1234' + ] + }, + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http({ + // allow injecting requests into the Hono app + server: fetchServer(app.fetch) + }) + } +}) + +console.info('Server listening on:') +node.getMultiaddrs().forEach(ma => { + console.info(ma.toString()) +}) diff --git a/examples/hono-server-over-libp2p/test/index.spec.js b/examples/hono-server-over-libp2p/test/index.spec.js new file mode 100644 index 0000000..1280ab6 --- /dev/null +++ b/examples/hono-server-over-libp2p/test/index.spec.js @@ -0,0 +1,29 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { matchOutput } from 'test-ipfs-example/node' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// Step 1 start server +process.stdout.write('node server.js\n') + +const { + process: server, + matches: addresses +} = await matchOutput(/Server listening on:\n(.*)\n/, 'node', [path.resolve(__dirname, '../src/server.js')]) + +const address = addresses.slice(1).map(line => line.trim()).pop() + +process.stdout.write('==================================================================\n') + +// Step 2 start client +process.stdout.write(`node client.js ${address}\n`) + +const { + process: client +} = await matchOutput(/Hello World!/g, 'node', [path.resolve(__dirname, '../src/client.js'), address]) + +process.stdout.write('==================================================================\n') + +client.kill() +server.kill() diff --git a/examples/js-libp2p-client-and-node-server/client.js b/examples/js-libp2p-client-and-node-server/client.js deleted file mode 100644 index d54a76a..0000000 --- a/examples/js-libp2p-client-and-node-server/client.js +++ /dev/null @@ -1,57 +0,0 @@ -/* eslint-disable no-console */ - -import { noise } from '@chainsafe/libp2p-noise' -import { yamux } from '@chainsafe/libp2p-yamux' -import { http } from '@libp2p/http-fetch' -import { tcp } from '@libp2p/tcp' -import { multiaddr } from '@multiformats/multiaddr' -import { createLibp2p } from 'libp2p' - -const node = await createLibp2p({ - // libp2p nodes are started by default, pass false to override this - start: false, - addresses: { - listen: [] - }, - transports: [tcp()], - connectionEncrypters: [noise()], - streamMuxers: [yamux()], - services: { http: http() } -}) - -// start libp2p -await node.start() -console.error('libp2p has started') - -// Read server multiaddr from the command line -const serverAddr = process.argv[2] -if (!serverAddr) { - console.error('Please provide the server multiaddr as an argument') - process.exit(1) -} - -let serverMA = multiaddr(serverAddr) - -const isHTTPTransport = serverMA.protos().find(p => p.name === 'http') // check if this is an http transport multiaddr -if (!isHTTPTransport && serverMA.getPeerId() === null) { - // Learn the peer id of the server. This lets us reuse the connection for all our HTTP requests. - // Otherwise js-libp2p will open a new connection for each request. - const conn = await node.dial(serverMA) - serverMA = serverMA.encapsulate(`/p2p/${conn.remotePeer.toString()}`) -} - -console.error('Making request to', `${serverMA.toString()}`) -try { - const resp = await node.services.http.fetch(new Request(`multiaddr:${serverMA}`)) - const respBody = await resp.text() - if (resp.status !== 200) { - throw new Error(`Unexpected status code: ${resp.status}`) - } - if (respBody !== 'Hello, World!') { - throw new Error(`Unexpected response body: ${respBody}`) - } - console.error('Got response:', respBody) -} finally { - // stop libp2p - await node.stop() -} diff --git a/examples/js-libp2p-client-and-node-server/server.js b/examples/js-libp2p-client-and-node-server/server.js deleted file mode 100644 index 2f6b1f4..0000000 --- a/examples/js-libp2p-client-and-node-server/server.js +++ /dev/null @@ -1,18 +0,0 @@ -/* eslint-disable no-console */ - -import http from 'http' - -const port = 55776 - -const server = http.createServer((req, res) => { - res.writeHead(200, { 'Content-Type': 'text/plain' }) - res.end('Hello, World!') -}) - -server.listen(port, () => { - console.error(`Server running at: http://localhost:${port}/`) - // Print multiaddr on stdout for test - console.error("Server's multiaddr is:") - console.log(`/dns4/localhost/tcp/${port}/http`) - console.log('') // Empty line to signal we have no more addresses (for test runner) -}) diff --git a/examples/libp2p-as-http-transport/README.md b/examples/libp2p-as-http-transport/README.md new file mode 100644 index 0000000..e3344b0 --- /dev/null +++ b/examples/libp2p-as-http-transport/README.md @@ -0,0 +1,61 @@ +# libp2p as a HTTP transport + +In this example we will see how we can use libp2p as a transport for HTTP +messages in Node.js. We will configure [Undici](https://github.com/nodejs/undici), +Node's [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) +implementation, and [http.request](https://nodejs.org/api/http.html#httprequesturl-options-callback) +to use libp2p as it's networking layer, in order for it to take advantage of +peer discovery, NAT traversal, multi-routes and other libp2p features. + +## Step 1 - start the server + +The script at [./src/server.js](./src/server.js) creates a basic [express](https://expressjs.com/) +app that has a simple "Hello world" route mounted on `/`. + +It creates a `http.Server` to pass HTTP requests to the express app, and finally +a libp2p node to make incoming `Stream`s conform to the `net.Socket` API and +pass them to the `http.Server`. + +Run the server with the following command: + +```console +node src/server.js +Server listening on: +/ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +/ip4/192.168.1.226/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +``` + +## Step 2 - run the Undici/fetch client + +The script at [./src/client-fetch.js](./src/client-fetch.js) uses a custom +[dispatcher](https://github.com/nodejs/undici/blob/main/docs/docs/api/Dispatcher.md) +with Node.js' built-in fetch implementation, [Undici](https://github.com/nodejs/undici), +to open a stream to the libp2p server over which HTTP messages are sent. + +Copy the URL that the server is listening on and pass it as a CLI arg: + +```console +node ./src/client-fetch.js /ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +GET /ip4/127.0.0.1/tcp/49153/p2p/12D3KooWKkShDk1oJDmBp4GsREbS8uqkiMhj9MJP9HGkWes7KavK 200 OK +Hello World! +``` + +## Step 3 - run the HTTP client + +The script at [./src/client-http.js](./src/client-http.js) uses a custom [Agent](https://nodejs.org/api/http.html#class-httpagent) +to work with the [request](https://nodejs.org/api/http.html#httprequestoptions-callback) +function from Node.js' `http` module in a similar way. + +Copy the URL that the server is listening on and pass it as a CLI arg: + +```console +node ./src/client-http.js /ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +GET /ip4/127.0.0.1/tcp/49153/p2p/12D3KooWKkShDk1oJDmBp4GsREbS8uqkiMhj9MJP9HGkWes7KavK 200 OK +Hello World! +``` + +## Next steps + +The configured peer receives all HTTP requests - can you write a basic version +of shared hosting where separate HTTP servers or apps might receive requests for +different requested hosts? diff --git a/examples/libp2p-as-http-transport/package.json b/examples/libp2p-as-http-transport/package.json new file mode 100644 index 0000000..ceff016 --- /dev/null +++ b/examples/libp2p-as-http-transport/package.json @@ -0,0 +1,33 @@ +{ + "name": "@libp2p/http-example-libp2p-as-http-transport", + "version": "1.0.0", + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "project": true, + "sourceType": "module" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "test": "test-node-example test/*" + }, + "dependencies": { + "@chainsafe/libp2p-noise": "^16.1.3", + "@chainsafe/libp2p-yamux": "^7.0.1", + "@libp2p/http": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "@libp2p/tcp": "^10.1.13", + "@multiformats/multiaddr": "^12.4.0", + "express": "^5.1.0", + "libp2p": "^2.8.8" + }, + "devDependencies": { + "aegir": "^47.0.16", + "test-ipfs-example": "^1.3.3" + }, + "private": true, + "type": "module" +} diff --git a/examples/libp2p-as-http-transport/src/client-fetch.js b/examples/libp2p-as-http-transport/src/client-fetch.js new file mode 100644 index 0000000..aedc9f6 --- /dev/null +++ b/examples/libp2p-as-http-transport/src/client-fetch.js @@ -0,0 +1,47 @@ +/* eslint-disable no-console */ + +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { tcp } from '@libp2p/tcp' +import { multiaddr } from '@multiformats/multiaddr' +import { createLibp2p } from 'libp2p' + +// Take the first argument as the path of the folder to add +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node client.js ') + process.exit(1) +} + +// turn the passed arg into a multiaddr +const addr = multiaddr(args[0]) + +const node = await createLibp2p({ + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http() + } +}) + +// this dispatcher will direct all requests to the passed PeerId/Multiaddr +const dispatcher = node.services.http.dispatcher(addr) + +// make an HTTP request over libp2p +const res = await fetch('http://example.com', { + dispatcher +}) + +console.info('GET', addr.toString(), res.status, res.statusText) +console.info(await res.text()) diff --git a/examples/libp2p-as-http-transport/src/client-http.js b/examples/libp2p-as-http-transport/src/client-http.js new file mode 100644 index 0000000..b6133e2 --- /dev/null +++ b/examples/libp2p-as-http-transport/src/client-http.js @@ -0,0 +1,62 @@ +/* eslint-disable no-console */ + +import { request } from 'node:http' +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { tcp } from '@libp2p/tcp' +import { multiaddr } from '@multiformats/multiaddr' +import { createLibp2p } from 'libp2p' + +// Take the first argument as the path of the folder to add +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node client.js ') + process.exit(1) +} + +// turn the passed arg into a multiaddr +const addr = multiaddr(args[0]) + +const node = await createLibp2p({ + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http() + }, + connectionMonitor: { + enabled: false + } +}) + +// this agent will direct all requests to the passed PeerId/Multiaddr +const agent = node.services.http.agent(addr) + +// make an HTTP request over libp2p +const req = request({ + host: 'example.com', + method: 'GET', + agent +}, (res) => { + console.info(req.method, addr.toString(), res.statusCode, res.statusMessage) + + res.on('data', (buf) => { + console.info(buf.toString()) + }) +}) + +req.on('error', (err) => { + console.error('problem with request', err) +}) + +req.end() diff --git a/examples/libp2p-as-http-transport/src/server.js b/examples/libp2p-as-http-transport/src/server.js new file mode 100644 index 0000000..3a7d0c4 --- /dev/null +++ b/examples/libp2p-as-http-transport/src/server.js @@ -0,0 +1,59 @@ +/* eslint-disable no-console */ + +import { createServer } from 'node:http' +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { nodeServer } from '@libp2p/http-server' +import { tcp } from '@libp2p/tcp' +import express from 'express' +import { createLibp2p } from 'libp2p' + +// this express app is where any business logic necessary to server HTTP +// resources will take place +const app = express() +app.get('/', (req, res) => { + console.info('sending response') + res.send('Hello World!') +}) + +// this Node.js http.Server will receive incoming socket connections and convert +// them to HTTP requests - note that we don't need to call `server.listen` - +// libp2p will provide the networking layer +const server = createServer() +server.on('request', (req, res) => { + console.info('incoming request', req.method, req.url) + app(req, res) +}) + +// create a libp2p node that listens on a TCP address +const node = await createLibp2p({ + addresses: { + listen: [ + '/ip4/0.0.0.0/tcp/0' + ] + }, + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http({ + // allow injecting requests into the Node.js http.Server + server: nodeServer(server) + }) + }, + connectionMonitor: { + enabled: false + } +}) + +console.info('Server listening on:') +node.getMultiaddrs().forEach(ma => { + console.info(ma.toString()) +}) diff --git a/examples/libp2p-as-http-transport/test/index.spec.js b/examples/libp2p-as-http-transport/test/index.spec.js new file mode 100644 index 0000000..f16fa6a --- /dev/null +++ b/examples/libp2p-as-http-transport/test/index.spec.js @@ -0,0 +1,39 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { matchOutput } from 'test-ipfs-example/node' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// Step 1 start server +process.stdout.write('node server.js\n') + +const { + process: server, + matches: addresses +} = await matchOutput(/Server listening on:\n(.*)\n/, 'node', [path.resolve(__dirname, '../src/server.js')]) + +const address = addresses.slice(1).map(line => line.trim()).pop() + +process.stdout.write('==================================================================\n') + +// Step 2 start fetch client +process.stdout.write(`node client-fetch.js ${address}\n`) + +const { + process: fetchClient +} = await matchOutput(/Hello World!/g, 'node', [path.resolve(__dirname, '../src/client-fetch.js'), address]) + +process.stdout.write('==================================================================\n') + +// Step 2 start fetch client +process.stdout.write(`node client-http.js ${address}\n`) + +const { + process: httpClient +} = await matchOutput(/Hello World!/g, 'node', [path.resolve(__dirname, '../src/client-http.js'), address]) + +process.stdout.write('==================================================================\n') + +fetchClient.kill() +httpClient.kill() +server.kill() diff --git a/examples/libp2p-over-http-server/README.md b/examples/libp2p-over-http-server/README.md new file mode 100644 index 0000000..d3162d5 --- /dev/null +++ b/examples/libp2p-over-http-server/README.md @@ -0,0 +1,64 @@ +# Serving libp2p over an Express app + +This example is the inverse of [../express-server-over-libp2p](../express-server-over-libp2p/README.md) +- instead of serving an Express app over libp2p streams, we're going to serve +libp2p protocols over HTTP. + +## Step 1 - start the server + +The script at [./src/server.js](./src/server.js) creates a libp2p node with a +custom HTTP protocol handler registered for `/test-http-protocol/1.0.0` in +addition to a `@libp2p/http-ping` handler. + +It creates a `http.Server` to accept incoming HTTP requests and uses the +`canHandle` function exported by `@libp2p/http-server/node` to try to delegate +processing of each incoming request to libp2p, otherwise it returns a 404. + +Run the server with the following command: + +```console +node src/server.js +Server listening on: +http://127.0.0.1:58135 +``` + +## Step 2 - run the HTTP client + +The script at [./src/client-http.js](./src/client-http.js) uses [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) +to interact with the libp2p server over HTTP without using any libp2p modules +itself. + +It invokes the custom HTTP protocol handler, then the `@libp2p/http-ping` +handler. + +Copy the URL that the server is listening on and pass it as a CLI arg: + +```console +node ./src/client-http.js http://127.0.0.1:58231 +GET http://127.0.0.1:58231/test-http-protocol/1.0.0 200 OK +Hello World! +GET http://127.0.0.1:58231/http-ping/1 200 OK +Ping took 2 ms +``` + +## Step 3 - run the libp2p client + +The script at [./src/client-libp2p.js](./src/client-libp2p.js) behaves in the +same way as the HTTP client, except it uses a libp2p node to send the HTTP +requests instead of [fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API). + +Copy the URL that the server is listening on and pass it as a CLI arg: + +```console +node client-libp2p.js http://127.0.0.1:58231 +GET http://127.0.0.1:58231 200 OK +Hello World! +Ping took 3 ms +``` + +## Next steps + +Experiment with the server - can you add your own custom HTTP handler and invoke +it from the client? + +Which is easier, using fetch or libp2p? diff --git a/examples/libp2p-over-http-server/package.json b/examples/libp2p-over-http-server/package.json new file mode 100644 index 0000000..6415cbb --- /dev/null +++ b/examples/libp2p-over-http-server/package.json @@ -0,0 +1,29 @@ +{ + "name": "@libp2p/http-example-libp2p-over-http-server", + "version": "1.0.0", + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "project": true, + "sourceType": "module" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "test": "test-node-example test/*" + }, + "dependencies": { + "@libp2p/http": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "@libp2p/http-ping": "~0.0.0", + "libp2p": "^2.8.8" + }, + "devDependencies": { + "aegir": "^47.0.16", + "test-ipfs-example": "^1.3.3" + }, + "private": true, + "type": "module" +} diff --git a/examples/libp2p-over-http-server/src/client-http.js b/examples/libp2p-over-http-server/src/client-http.js new file mode 100644 index 0000000..18aff3a --- /dev/null +++ b/examples/libp2p-over-http-server/src/client-http.js @@ -0,0 +1,45 @@ +/* eslint-disable no-console */ + +import { WELL_KNOWN_PROTOCOLS_PATH } from '@libp2p/http' +import { HTTP_PING_PROTOCOL } from '@libp2p/http-ping' +import { HTTP_TEST_PROTOCOL } from './common.js' + +// Take the first argument as the path of the folder to add +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node client.js ') +} + +// the HTTP address of the server +const uri = args[0] + +// first let's invoke the libp2p endpoint without using libp2p + +// 1. get the map of supported protocol id -> path +const wellKnownResponse = await fetch(new URL(`${uri}${WELL_KNOWN_PROTOCOLS_PATH}`)) +const protocols = await wellKnownResponse.json() + +// 2. make a request to the protocol handler +const result = await fetch(new URL(`${uri}${protocols[HTTP_TEST_PROTOCOL]?.path}`)) +console.info('GET', result.url, result.status, result.statusText) +console.info(await result.text()) + +// 3. let's use the ping protocol +const start = Date.now() +const body = Uint8Array.from(new Array(32).fill(0)) +const pong = await fetch(new URL(`${uri}${protocols[HTTP_PING_PROTOCOL]?.path}`), { + method: 'POST', + body +}) +console.info('GET', pong.url, pong.status, pong.statusText) +const buf = await pong.arrayBuffer() + +// check that we read all of the data +if (buf.byteLength !== body.byteLength) { + throw new Error('Short read') +} + +console.info('Ping took', Date.now() - start, 'ms') diff --git a/examples/libp2p-over-http-server/src/client-libp2p.js b/examples/libp2p-over-http-server/src/client-libp2p.js new file mode 100644 index 0000000..7413d06 --- /dev/null +++ b/examples/libp2p-over-http-server/src/client-libp2p.js @@ -0,0 +1,35 @@ +/* eslint-disable no-console */ + +import { http } from '@libp2p/http' +import { pingHTTP } from '@libp2p/http-ping' +import { createLibp2p } from 'libp2p' +import { HTTP_TEST_PROTOCOL } from './common.js' + +// Take the first argument as the path of the folder to add +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node client.js ') +} + +// the HTTP address of the server +const uri = args[0] + +// our client node +const node = await createLibp2p({ + services: { + http: http(), + pingHTTP: pingHTTP() + } +}) + +// make a HTTP request over libp2p +const res = await node.services.http.fetchProtocol(uri, HTTP_TEST_PROTOCOL) +console.info('GET', uri, res.status, res.statusText) +console.info(await res.text()) + +// make a ping request over libp2p +const pong = await node.services.pingHTTP.ping(uri) +console.info('Ping took', pong, 'ms') diff --git a/examples/libp2p-over-http-server/src/common.js b/examples/libp2p-over-http-server/src/common.js new file mode 100644 index 0000000..cc2b76c --- /dev/null +++ b/examples/libp2p-over-http-server/src/common.js @@ -0,0 +1 @@ +export const HTTP_TEST_PROTOCOL = '/test-http-protocol/1.0.0' diff --git a/examples/libp2p-over-http-server/src/server.js b/examples/libp2p-over-http-server/src/server.js new file mode 100644 index 0000000..cb06486 --- /dev/null +++ b/examples/libp2p-over-http-server/src/server.js @@ -0,0 +1,46 @@ +/* eslint-disable no-console */ + +import { createServer } from 'node:http' +import { http } from '@libp2p/http' +import { pingHTTP } from '@libp2p/http-ping' +import { canHandle } from '@libp2p/http-server/node' +import { createLibp2p } from 'libp2p' +import { HTTP_TEST_PROTOCOL } from './common.js' + +// create a libp2p node with a HTTP service that can serve arbitrary HTTP +// protocols and a HTTP ping handler that implements the HTTP ping protocol +const node = await createLibp2p({ + services: { + http: http(), + pingHTTP: pingHTTP() + } +}) + +// register a handler function for the passed protocol - it will be served at +// the protocol id path by default +node.services.http.handle(HTTP_TEST_PROTOCOL, { + handler: (req) => { + return new Response('Hello World!') + } +}) + +// this handler will return `true` if the request was handled by the libp2p +// node, otherwise it should be passed to an application server like express +// or otherwise handled +const handled = canHandle(node) + +// an HTTP server that listens on a port and receives incoming requests +const server = createServer() +server.on('request', (req, res) => { + if (handled(req, res)) { + return + } + + res.statusCode = 404 + res.end() +}) + +server.listen(0, () => { + console.info('Server listening on:') + console.info(`http://127.0.0.1:${server.address().port}`) +}) diff --git a/examples/libp2p-over-http-server/test/index.spec.js b/examples/libp2p-over-http-server/test/index.spec.js new file mode 100644 index 0000000..385585a --- /dev/null +++ b/examples/libp2p-over-http-server/test/index.spec.js @@ -0,0 +1,39 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { matchOutput } from 'test-ipfs-example/node' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// Step 1 start server +process.stdout.write('node server.js\n') + +const { + process: server, + matches: addresses +} = await matchOutput(/Server listening on:\n(.*)\n/, 'node', [path.resolve(__dirname, '../src/server.js')]) + +const address = addresses.slice(1).map(line => line.trim()).pop() + +process.stdout.write('==================================================================\n') + +// Step 2 start HTTP client +process.stdout.write(`node client-http.js ${address}\n`) + +const { + process: clientHTTP +} = await matchOutput(/Ping took/g, 'node', [path.resolve(__dirname, '../src/client-http.js'), address]) + +process.stdout.write('==================================================================\n') + +// Step 2 start client +process.stdout.write(`node client-libp2p.js ${address}\n`) + +const { + process: clientLibp2p +} = await matchOutput(/Ping took/g, 'node', [path.resolve(__dirname, '../src/client-libp2p.js'), address]) + +process.stdout.write('==================================================================\n') + +clientHTTP.kill() +clientLibp2p.kill() +server.kill() diff --git a/examples/package.json b/examples/package.json deleted file mode 100644 index 629fa68..0000000 --- a/examples/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "js-libp2p-whatwg-examples", - "version": "0.0.1", - "type": "module", - "dependencies": { - "@chainsafe/libp2p-noise": "^16.0.0", - "@chainsafe/libp2p-yamux": "^7.0.1", - "@hono/node-server": "^1.11.2", - "@libp2p/http-fetch": "file:..", - "@libp2p/peer-id": "^5.0.7", - "@libp2p/tcp": "^10.0.11", - "@multiformats/multiaddr": "^12.3.0", - "@multiformats/multiaddr-to-uri": "^10.1.0", - "hono": "^4.4.4", - "libp2p": "^2.2.1" - }, - "license": "Apache-2.0 OR MIT" -} diff --git a/examples/peer-id-auth/README.md b/examples/peer-id-auth/README.md index 4c09f1a..7dd326b 100644 --- a/examples/peer-id-auth/README.md +++ b/examples/peer-id-auth/README.md @@ -1,15 +1,43 @@ # HTTP Peer ID Auth This folder contains a simple HTTP server and client that in both Go and JS that -will run the HTTP Peer ID Auth protocol to mutually authenticate the client and -server's peer ID. +will run the [HTTP Peer ID Auth](https://github.com/libp2p/specs/blob/master/http/peer-id-auth.md) +protocol to mutually authenticate the client and server and allow them to +exchange peer IDs. Use this as an example for how to authenticate your server to libp2p clients (or any client that wants to authenticate a peer id). You can also use this to authenticate your client's peer id to a libp2p+HTTP server. -## Tests +## Step 1 - start a server + +You can start either the go server: + +```console +cd go-peer +go run . +``` + +..or the js server + +```console +node ./src/server.js +``` + +## Step 2 - start a client + +You can start either the go client: + +```console +cd go-peer +go run . client +``` + +..or the js client + +```console +node ./src/client.js +``` + +You should see both the client and server print out each other's PeerIds. -There is a simple tests that makes sure authentication works using a Go -{client,server} and a NodeJS {client,server}. In lieu, of a larger interop test -environment, this serves for now (pun intended). diff --git a/examples/peer-id-auth/go-peer/main.go b/examples/peer-id-auth/go-peer/main.go index 8e2f3ca..aee0a99 100644 --- a/examples/peer-id-auth/go-peer/main.go +++ b/examples/peer-id-auth/go-peer/main.go @@ -62,11 +62,14 @@ func runServer(privKey crypto.PrivKey) error { } func runClient(privKey crypto.PrivKey) error { + log.Printf("run auth") auth := httpauth.ClientPeerIDAuth{PrivKey: privKey} + log.Printf("run log") req, err := http.NewRequest("GET", "http://localhost:8001/log-my-id", nil) if err != nil { return err } + log.Printf("auth do") serverID, _, err := auth.AuthenticatedDo(http.DefaultClient, req) if err != nil { return err diff --git a/examples/peer-id-auth/node.js b/examples/peer-id-auth/node.js deleted file mode 100644 index 96f06ef..0000000 --- a/examples/peer-id-auth/node.js +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable no-console */ - -import { serve } from '@hono/node-server' -import { generateKeyPair } from '@libp2p/crypto/keys' -import { ClientAuth, HTTPPeerIDAuthProto, ServerAuth } from '@libp2p/http-fetch/auth' -import { WellKnownHandler, WELL_KNOWN_PROTOCOLS } from '@libp2p/http-fetch/well-known-handler' -import { peerIdFromPrivateKey } from '@libp2p/peer-id' -import { Hono } from 'hono' - -const privKey = await generateKeyPair('Ed25519') -const myID = peerIdFromPrivateKey(privKey) -const wellKnownHandler = new WellKnownHandler() - -const args = process.argv.slice(2) -if (args.length === 1 && args[0] === 'client') { - // Client mode - const client = new ClientAuth(privKey) - const { peer: serverID } = await client.authenticatedFetch('http://localhost:8001/log-my-id') - console.log('Server ID:', serverID.toString()) - console.log('Client ID:', myID.toString()) - process.exit(0) -} -// Server mode - -const httpServerAuth = new ServerAuth(privKey, (_) => true, { logger: console }) - -const app = new Hono() -app.get(WELL_KNOWN_PROTOCOLS, async (c) => { - return wellKnownHandler.handleRequest(c.req) -}) - -// Register HTTP ping protocol -app.all('/auth', (c) => { - return httpServerAuth.httpHandler(addHeadersProxy(c.req)) -}) -wellKnownHandler.registerProtocol(HTTPPeerIDAuthProto, '/auth') - -const logMyIDHandler = httpServerAuth.withAuth(async (clientId, req) => { - console.log('Client ID:', clientId.toString()) - return new Response('', { status: 200 }) -}) - -app.all('/log-my-id', async (c) => { - return logMyIDHandler(addHeadersProxy(c.req)) -}) -wellKnownHandler.registerProtocol('/log-my-id/1', '/log-my-id') - -const server = serve({ - fetch: app.fetch, - port: 8001, - hostname: '127.0.0.1' -}) - -console.log('Server ID:', myID.toString()) - -// wait for SIGINT -await new Promise(resolve => process.on('SIGINT', resolve)) - -// Stop the http server -server.close() - -// Proxy helper to handle the difference in how the standard Request type -// exposes headers and how hono's Request type exposes headers. -// The standard Request type exposes headers as a Headers object, while -// hono's Request type has a function `header(name: string): string | null` to get the header -function addHeadersProxy (req) { - return new Proxy(req, { - get: (target, prop) => { - if (prop === 'headers') { - return { - get: (header) => { - return req.header(header) - } - } - } - return target[prop] - } - }) -} diff --git a/examples/peer-id-auth/package.json b/examples/peer-id-auth/package.json new file mode 100644 index 0000000..4c15cb2 --- /dev/null +++ b/examples/peer-id-auth/package.json @@ -0,0 +1,30 @@ +{ + "name": "@libp2p/http-example-peer-id-auth", + "version": "1.0.0", + "description": "How to authenticate peers over HTTP", + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "project": true, + "sourceType": "module" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "test": "test-node-example test/*" + }, + "dependencies": { + "@libp2p/http": "~0.0.0", + "@libp2p/http-peer-id-auth": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "libp2p": "^2.8.8" + }, + "devDependencies": { + "aegir": "^47.0.16", + "test-ipfs-example": "^1.3.3" + }, + "private": true, + "type": "module" +} diff --git a/examples/peer-id-auth/runTest.sh b/examples/peer-id-auth/runTest.sh deleted file mode 100755 index 752e5b5..0000000 --- a/examples/peer-id-auth/runTest.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# A simple script that runs the auth flow using both Go and NodeJS servers and clients. -# The server prints its peer ID to stdout. -# The client prints the server's peer ID to stdout. -# If both stdout match, the test passes. If they differ the test fails. -# Exit code 0 indicates success. - -# Function to cleanup temporary directory -cleanup() { - rm -rf "$TMPDIR" -} - -stop_server() { - local pid=$1 - kill "$pid" - wait "$pid" > /dev/null 2>&1 || true -} - -TMPDIR=$(mktemp -d) -trap cleanup EXIT - -# Build Go code -(cd go-peer && go build -o ../go-node main.go) - -GO_SERVER="./go-node" -GO_CLIENT="./go-node client" - -NODE_SERVER="node node.js" -NODE_CLIENT="node node.js client" - -# Define server arrays -SERVERS=("$GO_SERVER" "$NODE_SERVER") -CLIENTS=("$GO_CLIENT" "$NODE_CLIENT") - -for server in "${SERVERS[@]}"; do - for client in "${CLIENTS[@]}"; do - echo "Running server='$server' client='$client'" - $server > "$TMPDIR/server.out" & - SERVER_PID=$! - sleep 1 - eval $client > "$TMPDIR/client.out" - stop_server "$SERVER_PID" - - if ! diff "$TMPDIR/server.out" "$TMPDIR/client.out"; then - echo "Outputs differ" - echo "Server:" - cat "$TMPDIR/server.out" - echo "Client:" - cat "$TMPDIR/client.out" - echo "Diff:" - diff -u "$TMPDIR/server.out" "$TMPDIR/client.out" - exit 1 - fi - done -done - -exit 0 diff --git a/examples/peer-id-auth/src/client.js b/examples/peer-id-auth/src/client.js new file mode 100644 index 0000000..7613c8b --- /dev/null +++ b/examples/peer-id-auth/src/client.js @@ -0,0 +1,24 @@ +/* eslint-disable no-console */ + +import { http } from '@libp2p/http' +import { peerIdAuth } from '@libp2p/http/middleware' +import { createLibp2p } from 'libp2p' + +// create a libp2p node that can act as a client +const node = await createLibp2p({ + services: { + http: http() + } +}) + +const res = await node.services.http.fetch('http://localhost:8001/log-my-id', { + middleware: [ + peerIdAuth() + ] +}) + +console.info('GET', res.url, res.status, res.statusText) +console.info(await res.text()) + +console.log('Client ID:', node.peerId.toString()) +console.log('Server ID:', res.headers.get('x-libp2p-peer-id')) diff --git a/examples/peer-id-auth/src/server.js b/examples/peer-id-auth/src/server.js new file mode 100644 index 0000000..6bd3be3 --- /dev/null +++ b/examples/peer-id-auth/src/server.js @@ -0,0 +1,54 @@ +/* eslint-disable no-console */ + +import { createServer } from 'node:http' +import { http } from '@libp2p/http' +import { authenticatedRoute } from '@libp2p/http/routes' +import { HTTP_PEER_ID_AUTH_PROTOCOL } from '@libp2p/http-peer-id-auth' +import { canHandle } from '@libp2p/http-server/node' +import { createLibp2p } from 'libp2p' + +const node = await createLibp2p({ + services: { + http: http() + } +}) + +node.services.http.handle(HTTP_PEER_ID_AUTH_PROTOCOL, authenticatedRoute({ + path: '/auth', + handler: (req, peerId) => { + console.log('Client ID:', peerId.toString()) + + return new Response('', { + status: 200 + }) + } +})) + +node.services.http.handle('/log-my-id/1', authenticatedRoute({ + path: '/log-my-id', + handler: (req, peerId) => { + console.log('Client ID:', peerId.toString()) + + return new Response('', { + status: 200 + }) + } +})) + +const handled = canHandle(node) + +const server = createServer() +server.on('request', (req, res) => { + if (handled(req, res)) { + return + } + + res.statusCode = 404 + res.end() +}) + +server.listen(8001, () => { + console.info('Server listening on:') + console.info(`http://127.0.0.1:${server.address().port}`) + console.log('Server ID:', node.peerId.toString()) +}) diff --git a/examples/peer-id-auth/test/index.spec.js b/examples/peer-id-auth/test/index.spec.js new file mode 100644 index 0000000..61801be --- /dev/null +++ b/examples/peer-id-auth/test/index.spec.js @@ -0,0 +1,51 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { matchOutput, execa } from 'test-ipfs-example/node' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +await execa('go', ['build', '-o', 'go-node', 'main.go'], { + cwd: path.resolve(__dirname, '../go-peer') +}) + +// Step 1 start go server +process.stdout.write('./go-peer/go-node\n') + +const { + process: goServer +} = await matchOutput(/listening on/g, './go-peer/go-node') + +process.stdout.write('==================================================================\n') + +// Step 2 start js client +process.stdout.write('node src/client.js\n') + +const { + process: jsClient +} = await matchOutput(/Server ID/g, 'node', [path.resolve(__dirname, '../src/client.js')]) + +process.stdout.write('==================================================================\n') + +jsClient.kill() +goServer.kill() + +// Step 1 start go server +process.stdout.write('./go-peer/go-node\n') + +const { + process: jsServer +} = await matchOutput(/listening on/g, './src/server.js') + +process.stdout.write('==================================================================\n') + +// Step 2 start js client +process.stdout.write('node src/client.js\n') + +const { + process: goClient +} = await matchOutput(/Server ID/g, './go-peer/go-node', ['client']) + +process.stdout.write('==================================================================\n') + +jsServer.kill() +goClient.kill() diff --git a/examples/serving-websites-from-web-browsers/README.md b/examples/serving-websites-from-web-browsers/README.md new file mode 100644 index 0000000..154308c --- /dev/null +++ b/examples/serving-websites-from-web-browsers/README.md @@ -0,0 +1,87 @@ +# Serving websites from web browsers with libp2p + +With libp2p providing the networking layer for HTTP servers, you are no longer +limited to servers being in the cloud or on servers with fixed addresses. + +Instead a web browser listening on a WebRTC address can serve web pages in the +same way a Node.js server can. + +Finally, the distributed web! + +## Step 1 - start the relay + +In order for a browser node to be dialable over WebRTC, it needs a mechanism to +perform an [SDP handshake](https://en.wikipedia.org/wiki/Session_Description_Protocol). + +libp2p uses Circuit Relay servers to do this. + +```console +npm run relay + +> @libp2p/http-example-serving-websites-from-web-browsers@1.0.0 relay +> node ./src/relay.js + +Relay listening on: +/ip4/127.0.0.1/tcp/50040/ws/p2p/12D3KooWG7UmwmLGGfg7QhciMoEG7Zirz7ecCcAir26uZwPLEF62 +/ip4/192.168.1.226/tcp/50040/ws/p2p/12D3KooWG7UmwmLGGfg7QhciMoEG7Zirz7ecCcAir26uZwPLEF62 +``` + +## Step 2 - start the browser-server + +[index.js]('./index.js) in this directory contains code to run a libp2p node +that listens on the `/http/1.1` protocol for incoming requests and hands them +off to a web server created using `createServer` from +`@libp2p/http-server/node`. + +This function implements the same API as [http.createServer](https://nodejs.org/api/http.html#httpcreateserveroptions-requestlistener) +just without depending on any Node.js internals so you can use it in a web +browser with no other dependencies! + +Start the webapp (your browser should open): + +```console +npm start + + VITE v6.3.3 ready in 63 ms + + ➜ Local: http://localhost:5173/ + ➜ Network: use --host to expose + ➜ press h + enter to show help +``` + +Paste one of the relay addresses into the text box and click "Connect". + +Eventually one or more listening addresses should appear on the page. + +## Step 3 - run the HTTP proxy + +Unfortunately we still can't listen on a socket in a web browser, so if we want +to see this working in a browser window we'll need to proxy incoming HTTP +requests. + +Start the proxy server with one of the listening addresses from the web page: + +```console +npm run proxy -- /ip4/127.0.0.1/tcp/57457/ws/p2p/12Relay.../p2p-circuit/webrtc/p2p/12Browser + +Proxy listening on: +http://127.0.0.1:62305 +``` + +## Step 4 - open the proxy URL in another browser + +Open the proxy URL in a web browser and you should see the page served from +the first browser over a libp2p stream. + +## Next steps + +Can you serve images from the server? + +What about adding REST-like endpoints that you can invoke from the page served +by the first web page? + +`@libp2p/http-server/node` also exports a `createWebSocketServer` function, can +you use it to serve WebSocket connections from browsers? + +Libp2p has a `@libp2p/websocket` transport - can you implement your own +transport that runs libp2p over websockets over HTTP over libp2p over WebRTC? diff --git a/examples/serving-websites-from-web-browsers/index.html b/examples/serving-websites-from-web-browsers/index.html new file mode 100644 index 0000000..52235ba --- /dev/null +++ b/examples/serving-websites-from-web-browsers/index.html @@ -0,0 +1,46 @@ + + + + + + js-libp2p serving websites + + + +

libp2p Browser Web Server Example

+

This example demonstrates running a web server in a browser

+
+
+ +

Enter a relay address and click "Connect"

+ + +

Listening Addresses

+
    +
  • None
  • +
+
+
+
+

Log

+

+    
+ + + diff --git a/examples/serving-websites-from-web-browsers/index.js b/examples/serving-websites-from-web-browsers/index.js new file mode 100644 index 0000000..6cec1a7 --- /dev/null +++ b/examples/serving-websites-from-web-browsers/index.js @@ -0,0 +1,116 @@ +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { circuitRelayTransport } from '@libp2p/circuit-relay-v2' +import { devToolsMetrics } from '@libp2p/devtools-metrics' +import { http } from '@libp2p/http' +import { nodeServer } from '@libp2p/http-server' +import { createServer } from '@libp2p/http-server/node' +import { identify } from '@libp2p/identify' +import { ping } from '@libp2p/ping' +import { webRTC } from '@libp2p/webrtc' +import { webSockets } from '@libp2p/websockets' +import { multiaddr } from '@multiformats/multiaddr' +import { WebRTC } from '@multiformats/multiaddr-matcher' +import { createLibp2p } from 'libp2p' + +const WEB_PAGE = ` + + + + + A website served from a web browser + + +

This web page was served from a browser

+

The user agent of the browser was ${navigator.userAgent}

+ + +` + +const server = createServer((req, res) => { + if (req.url === '/' || req.url === '/index.html') { + appendOutput(`${req.method} ${req.url} 200`) + res.write(WEB_PAGE) + res.end() + return + } + + appendOutput(`${req.method} ${req.url} 404`) + res.write('404 Not found') + res.end() +}) + +const DOM = { + dialMultiaddrInput: () => document.getElementById('dial-multiaddr-input'), + dialMultiaddrButton: () => document.getElementById('dial-multiaddr-button'), + + output: () => document.getElementById('output'), + + listeningAddressesList: () => document.getElementById('listening-addresses') +} + +const appendOutput = (line) => { + DOM.output().innerText += `${line}\n` +} + +const libp2p = await createLibp2p({ + addresses: { + listen: [ + // make a reservation on any discovered relays - this will let other + // peers use the relay to contact us + '/p2p-circuit', + // create listeners for incoming WebRTC connection attempts on on all + // available Circuit Relay connections + '/webrtc' + ] + }, + transports: [ + // the WebSocket transport lets us dial a local relay + webSockets(), + // support dialing/listening on WebRTC addresses + webRTC(), + // support dialing/listening on Circuit Relay addresses + circuitRelayTransport() + ], + // a connection encrypter is necessary to dial the relay + connectionEncrypters: [noise()], + // a stream muxer is necessary to dial the relay + streamMuxers: [yamux()], + connectionGater: { + denyDialMultiaddr: () => { + // by default we refuse to dial local addresses from browsers since they + // are usually sent by remote peers broadcasting undialable multiaddrs and + // cause errors to appear in the console but in this example we are + // explicitly connecting to a local node so allow all addresses + return false + } + }, + services: { + identify: identify(), + http: http({ + server: nodeServer(server) + }), + ping: ping() + }, + metrics: devToolsMetrics() +}) + +// update listening addresses +libp2p.addEventListener('self:peer:update', () => { + const multiaddrs = libp2p.getMultiaddrs() + .filter(ma => WebRTC.exactMatch(ma)) + .map((ma) => { + const el = document.createElement('li') + el.textContent = ma.toString() + return el + }) + DOM.listeningAddressesList().replaceChildren(...multiaddrs) +}) + +// dial remote peer +DOM.dialMultiaddrButton().onclick = async () => { + const ma = multiaddr(DOM.dialMultiaddrInput().value) + appendOutput(`Dialing '${ma}'`) + await libp2p.dial(ma) + appendOutput(`Connected to '${ma}'`) +} diff --git a/examples/serving-websites-from-web-browsers/package.json b/examples/serving-websites-from-web-browsers/package.json new file mode 100644 index 0000000..8f2d477 --- /dev/null +++ b/examples/serving-websites-from-web-browsers/package.json @@ -0,0 +1,45 @@ +{ + "name": "@libp2p/http-example-serving-websites-from-web-browsers", + "version": "1.0.0", + "description": "How to serve websites from web browsers using libp2p", + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "project": true, + "sourceType": "module" + } + }, + "scripts": { + "start": "vite", + "build": "vite build", + "relay": "node ./src/relay.js", + "proxy": "node ./src/proxy.js", + "test": "npm run build && test-browser-example test", + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check" + }, + "dependencies": { + "@chainsafe/libp2p-noise": "^16.1.3", + "@chainsafe/libp2p-yamux": "^7.0.1", + "@libp2p/circuit-relay-v2": "^3.2.14", + "@libp2p/devtools-metrics": "^1.2.17", + "@libp2p/http": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "@libp2p/identify": "^3.0.32", + "@libp2p/ping": "^2.0.32", + "@libp2p/webrtc": "^5.2.15", + "@libp2p/websockets": "^9.2.13", + "@multiformats/multiaddr": "^12.4.0", + "@multiformats/multiaddr-matcher": "^1.7.2", + "it-byte-stream": "^2.0.2", + "libp2p": "^2.8.8" + }, + "devDependencies": { + "aegir": "^47.0.16", + "test-ipfs-example": "^1.3.3", + "vite": "^6.3.5" + }, + "private": true, + "type": "module" +} diff --git a/examples/serving-websites-from-web-browsers/src/proxy.js b/examples/serving-websites-from-web-browsers/src/proxy.js new file mode 100644 index 0000000..e0b299b --- /dev/null +++ b/examples/serving-websites-from-web-browsers/src/proxy.js @@ -0,0 +1,85 @@ +/* eslint-disable no-console */ + +import { createServer } from 'node:net' +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { circuitRelayServer, circuitRelayTransport } from '@libp2p/circuit-relay-v2' +import { HTTP_PROTOCOL } from '@libp2p/http' +import { identify } from '@libp2p/identify' +import { ping } from '@libp2p/ping' +import { webRTC } from '@libp2p/webrtc' +import { webSockets } from '@libp2p/websockets' +import { multiaddr } from '@multiformats/multiaddr' +import { byteStream } from 'it-byte-stream' +import { createLibp2p } from 'libp2p' + +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node proxy.js ') + process.exit(1) +} + +const address = multiaddr(args[0]) + +// create a libp2p node that functions as proxy for the webserver running in a +// web browser +const node = await createLibp2p({ + transports: [ + webRTC(), + circuitRelayTransport(), + webSockets() + ], + connectionEncrypters: [noise()], + streamMuxers: [yamux()], + services: { + identify: identify(), + relay: circuitRelayServer(), + ping: ping() + } +}) + +const server = createServer((socket) => { + Promise.resolve() + .then(async () => { + const stream = await node.dialProtocol(address, HTTP_PROTOCOL, { + signal: AbortSignal.timeout(5_000) + }) + + const bytes = byteStream(stream) + + socket.on('data', buf => { + bytes.write(buf) + }) + socket.on('close', () => { + stream.close() + }) + socket.on('error', (err) => { + stream.abort(err) + }) + + while (true) { + const buf = await bytes.read() + + if (buf == null) { + break + } + + socket.write(buf.subarray()) + } + + socket.end() + stream.close() + }) + .catch(err => { + console.error('failed to proxy request', err) + socket.destroy() + }) +}) + +server.listen(0, () => { + console.info('Proxy listening on:') + console.info(`http://127.0.0.1:${server.address().port}`) +}) diff --git a/examples/serving-websites-from-web-browsers/src/relay.js b/examples/serving-websites-from-web-browsers/src/relay.js new file mode 100644 index 0000000..e0287de --- /dev/null +++ b/examples/serving-websites-from-web-browsers/src/relay.js @@ -0,0 +1,37 @@ +/* eslint-disable no-console */ + +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { circuitRelayServer } from '@libp2p/circuit-relay-v2' +import { identify } from '@libp2p/identify' +import { ping } from '@libp2p/ping' +import { webSockets } from '@libp2p/websockets' +import { createLibp2p } from 'libp2p' + +// create a libp2p node that functions as Circuit Relay server +const node = await createLibp2p({ + addresses: { + listen: [ + '/ip4/127.0.0.1/tcp/0/ws' + ] + }, + transports: [ + webSockets() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + identify: identify(), + relay: circuitRelayServer(), + ping: ping() + } +}) + +console.info('Relay listening on:') +node.getMultiaddrs().forEach(ma => { + console.info(ma.toString()) +}) diff --git a/examples/serving-websites-from-web-browsers/test-results/.last-run.json b/examples/serving-websites-from-web-browsers/test-results/.last-run.json new file mode 100644 index 0000000..cbcc1fb --- /dev/null +++ b/examples/serving-websites-from-web-browsers/test-results/.last-run.json @@ -0,0 +1,4 @@ +{ + "status": "passed", + "failedTests": [] +} \ No newline at end of file diff --git a/examples/serving-websites-from-web-browsers/test/index.spec.js b/examples/serving-websites-from-web-browsers/test/index.spec.js new file mode 100644 index 0000000..e948786 --- /dev/null +++ b/examples/serving-websites-from-web-browsers/test/index.spec.js @@ -0,0 +1,86 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { setup, expect } from 'test-ipfs-example/browser' +import { matchOutput } from 'test-ipfs-example/node' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// Setup +const test = setup() + +// DOM +const connectBtn = '#dial-multiaddr-button' +const connectAddr = '#dial-multiaddr-input' +const output = 'body' +const listeningAddresses = '#listening-addresses' + +let url + +test.describe('serving websites from a web browser:', () => { + let relayNode + let relayNodeAddr + let proxyNode + let proxyNodeAddr + + test.beforeAll(async ({ servers }, testInfo) => { + testInfo.setTimeout(5 * 60_000) + + const { + process: relayProc, + matches: relayAddr + } = await matchOutput(/Relay listening on:\n(.*)\n/, 'node', [path.resolve(__dirname, '../src/relay.js')]) + + relayNode = relayProc + relayNodeAddr = relayAddr[1] + + url = servers[0].url + }, {}) + + test.afterAll(() => { + proxyNode?.kill() + relayNode?.kill() + }) + + test.beforeEach(async ({ page }) => { + await page.goto(url) + }) + + test('should serve a web page via the proxy', async ({ page: pageA, context }) => { + // connect the first page to the relay + const webRTCAddressA = await dialRelay(pageA, relayNodeAddr) + + // start the proxy + const { + process: proxyProc, + matches: proxyAddr + } = await matchOutput(/Proxy listening on:\n(.*)\n/, 'node', [path.resolve(__dirname, '../src/proxy.js'), webRTCAddressA]) + + proxyNode = proxyProc + proxyNodeAddr = proxyAddr[1] + + // load second page + const pageB = await context.newPage() + await pageB.goto(proxyNodeAddr) + + const outputLocator = pageB.locator(output) + await expect(outputLocator).toContainText('This web page was served from a browser') + }) +}) + +async function dialRelay (page, address) { + // add the relay multiaddr to the input field and submit + await page.fill(connectAddr, address) + await page.click(connectBtn) + + const outputLocator = page.locator(output) + await expect(outputLocator).toContainText(`Dialing '${address}'`) + await expect(outputLocator).toContainText(`Connected to '${address}'`) + + const multiaddrsLocator = page.locator(listeningAddresses) + await expect(multiaddrsLocator).toHaveText(/webrtc/) + + const multiaddrs = await page.textContent(listeningAddresses) + const addr = multiaddrs.split(address).filter(str => str.includes('webrtc')).pop() + + return address + addr +} diff --git a/examples/serving-websites-from-web-browsers/vite.config.js b/examples/serving-websites-from-web-browsers/vite.config.js new file mode 100644 index 0000000..8de4e24 --- /dev/null +++ b/examples/serving-websites-from-web-browsers/vite.config.js @@ -0,0 +1,11 @@ +export default { + build: { + target: 'es2022' + }, + optimizeDeps: { + esbuildOptions: { target: 'es2022', supported: { bigint: true } } + }, + server: { + open: true + } +} diff --git a/examples/test-runner/README.md b/examples/test-runner/README.md deleted file mode 100644 index d1ee34f..0000000 --- a/examples/test-runner/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# A simple way to test examples - -Usage: - -Inside an example folder: - -`go run ../test-runner/main.go` diff --git a/examples/test-runner/main.go b/examples/test-runner/main.go deleted file mode 100644 index 48c545e..0000000 --- a/examples/test-runner/main.go +++ /dev/null @@ -1,139 +0,0 @@ -package main - -import ( - "bufio" - "context" - "flag" - "fmt" - "log" - "os" - "os/exec" - "regexp" - "sync" -) - -func main() { - hasProxy := flag.Bool("hasProxy", false, "Does this test have a proxy server?") - flag.Parse() - if err := runTest(*hasProxy); err != nil { - log.Fatal(err) - } -} - -func runTest(hasProxy bool) error { - var wg sync.WaitGroup - defer wg.Wait() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - serverCmd, serverMultiaddrs, err := runServer(ctx) - if err != nil { - return err - } - go func() { - wg.Add(1) - defer wg.Done() - serverCmd.Wait() - }() - log.Println("server multiaddrs read:", serverMultiaddrs) - - if hasProxy { - buildProxy() - cmd, proxyAddr, err := runProxy(ctx, serverMultiaddrs[0]) // Only proxy the first - if err != nil { - return err - } - go func() { - wg.Add(1) - defer wg.Done() - cmd.Wait() - }() - - return runClient(proxyAddr) - } - - for _, serverMultiaddr := range serverMultiaddrs { - err := runClient(serverMultiaddr) - if err != nil { - return err - } - } - return nil -} - -func runServer(ctx context.Context) (*exec.Cmd, []string, error) { - serverCmd := exec.CommandContext(ctx, "node", "server.js") - serverCmd.Stderr = os.Stderr - serverCmd.Cancel = func() error { - serverCmd.Process.Signal(os.Interrupt) - return nil - } - stdoutPipe, err := serverCmd.StdoutPipe() - if err != nil { - return nil, nil, err - } - - serverCmd.Start() - - addrs := make([]string, 0, 2) - bufReader := bufio.NewReader(stdoutPipe) - for { - s, err := bufReader.ReadString('\n') - if err != nil { - return nil, nil, err - } - s = s[:len(s)-1] // Remove newline - if s == "" { - break - } - addrs = append(addrs, s) - } - return serverCmd, addrs, nil -} - -func runClient(serverMultiaddr string) error { - clientCmd := exec.Command("node", "client.js", serverMultiaddr) - clientCmd.Stderr = os.Stderr - return clientCmd.Run() -} - -func buildProxy() { - buildCmd := exec.Command("go", "build", "-o", "proxy", "main.go") - buildCmd.Dir = "./proxy" - buildCmd.Stderr = os.Stderr - buildCmd.Stdout = os.Stdout - buildCmd.Run() -} - -var r, _ = regexp.Compile("/tcp/([0-9]+)") - -func runProxy(ctx context.Context, serverMultiaddr string) (*exec.Cmd, string, error) { - matches := r.FindStringSubmatch(serverMultiaddr) - if len(matches) != 2 { - return nil, "", fmt.Errorf("Could not find port in server multiaddr") - } - port := matches[1] - proxyCmd := exec.CommandContext(ctx, "./proxy", "-proxy-target", "http://localhost:"+port) - proxyCmd.Cancel = func() error { - proxyCmd.Process.Signal(os.Interrupt) - return nil - } - proxyCmd.Dir = "./proxy" - proxyCmd.Stderr = os.Stderr - stdoutPipe, err := proxyCmd.StdoutPipe() - if err != nil { - log.Fatal(err) - } - - proxyCmd.Start() - bufReader := bufio.NewReader(stdoutPipe) - s, err := bufReader.ReadString('\n') - if err != nil { - if proxyCmd.Process != nil { - proxyCmd.Process.Signal(os.Interrupt) - } - log.Fatal(err) - } - return proxyCmd, s, nil -} diff --git a/examples/two-js-peers/client.js b/examples/two-js-peers/client.js deleted file mode 100644 index 0d2ef5d..0000000 --- a/examples/two-js-peers/client.js +++ /dev/null @@ -1,69 +0,0 @@ -/* eslint-disable no-console */ - -import { noise } from '@chainsafe/libp2p-noise' -import { yamux } from '@chainsafe/libp2p-yamux' -import { http } from '@libp2p/http-fetch' -import { sendPing } from '@libp2p/http-fetch/ping' -import { peerIdFromString } from '@libp2p/peer-id' -import { tcp } from '@libp2p/tcp' -import { multiaddr } from '@multiformats/multiaddr' -import { createLibp2p } from 'libp2p' - -const node = await createLibp2p({ - // libp2p nodes are started by default, pass false to override this - start: false, - addresses: { - listen: [] - }, - transports: [tcp()], - connectionEncrypters: [noise()], - streamMuxers: [yamux()], - services: { http: http() } -}) - -// start libp2p -await node.start() -console.error('libp2p has started') - -// Read server multiaddr from the command line -const serverAddr = process.argv[2] -if (!serverAddr) { - console.error('Please provide the server multiaddr as an argument') - process.exit(1) -} - -let serverMA = multiaddr(serverAddr) - -const isHTTPTransport = serverMA.protos().find(p => p.name === 'http') // check if this is an http transport multiaddr -if (!isHTTPTransport && serverMA.getPeerId() === null) { - // Learn the peer id of the server. This lets us reuse the connection for all our HTTP requests. - // Otherwise js-libp2p will open a new connection for each request. - const conn = await node.dial(serverMA) - serverMA = serverMA.encapsulate(`/p2p/${conn.remotePeer.toString()}`) -} - -console.error('Making request to', `${serverMA.toString()}`) -try { - for (let i = 0; i < 2; i++) { - const start = new Date().getTime() - await sendPing(node, serverMA) - const end = new Date().getTime() - console.error('Got response! took', end - start, 'ms') - console.log(end - start) - // sleep 1s - await new Promise(resolve => setTimeout(resolve, 1000)) - } - - // Making a request using only the server's peer id works too, but only in the - // non-http transport case. PeerIDs on an HTTP Transport is not implemented - // yet see https://github.com/libp2p/specs/pull/564. - if (!isHTTPTransport) { - const start = new Date().getTime() - await sendPing(node, peerIdFromString(serverMA.getPeerId())) - const end = new Date().getTime() - console.error('Got response! took', end - start, 'ms') - console.log(end - start) - } -} finally { - await node.stop() -} diff --git a/examples/two-js-peers/server.js b/examples/two-js-peers/server.js deleted file mode 100644 index eaeaca5..0000000 --- a/examples/two-js-peers/server.js +++ /dev/null @@ -1,38 +0,0 @@ -/* eslint-disable no-console */ - -import { noise } from '@chainsafe/libp2p-noise' -import { yamux } from '@chainsafe/libp2p-yamux' -import { http } from '@libp2p/http-fetch' -import { PING_PROTOCOL_ID, servePing } from '@libp2p/http-fetch/ping' -import { tcp } from '@libp2p/tcp' -import { createLibp2p } from 'libp2p' - -const node = await createLibp2p({ - // libp2p nodes are started by default, pass false to override this - start: false, - addresses: { - listen: ['/ip4/127.0.0.1/tcp/8000'] - }, - transports: [tcp()], - connectionEncrypters: [noise()], - streamMuxers: [yamux()], - services: { http: http() } -}) - -// start libp2p -await node.start() -console.error('libp2p has started') - -const listenAddrs = node.getMultiaddrs() -console.error('libp2p is listening on the following address:') -console.log(listenAddrs[0].toString()) -console.log('') // Empty line to signal we have no more addresses (for test runner) - -node.services.http.handleHTTPProtocol(PING_PROTOCOL_ID, '/ping', servePing) - -// sleep 100s -await new Promise(resolve => setTimeout(resolve, 100000)) - -// stop libp2p -await node.stop() -console.error('libp2p has stopped') diff --git a/examples/websockets-over-libp2p/README.md b/examples/websockets-over-libp2p/README.md new file mode 100644 index 0000000..27ce2e3 --- /dev/null +++ b/examples/websockets-over-libp2p/README.md @@ -0,0 +1,55 @@ +# Serving an Express app over libp2p + +In this example we will start a libp2p node that listens for incoming streams +that use the `/http/1.1` protocol. + +It will convert the incoming stream to a [http.IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage) +and hand it off to a Node.js [http.Server](https://nodejs.org/api/http.html#class-httpserver), +then write data passed to the corresponding [http.ServerResponse](https://nodejs.org/api/http.html#class-httpserverresponse) +back into the stream for the client to read. + +## Step 1 - start the server + +The script at [./src/server.js](./src/server.js) creates a basic [express](https://expressjs.com/) +app that has a simple "Hello world" route mounted on `/`. + +It creates a `http.Server` to pass HTTP requests to the express app, and finally +a libp2p node to make incoming `Stream`s conform to the `net.Socket` API and +pass them to the `http.Server`. + +Run the server with the following command: + +```console +node src/server.js +Server listening on: +/ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +/ip4/192.168.1.226/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +``` + +## Step 2 - run the client + +The script at [./src/client.js](./src/client.js) starts a libp2p node with the +TCP transport, accepts a command line argument of a multiaddr and makes a HTTP +request to it over a libp2p stream. + +Copy one of the multiaddrs the server is listening on and pass it as a CLI arg: + +```console +node ./src/client.js /ip4/127.0.0.1/tcp/1234/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt +GET /ip4/127.0.0.1/tcp/55265/p2p/12D3KooWPUq3SjKGmVz4fhqMHZpZ185ZErfusp9x4QFgqwVCTxWt 200 OK +Hello World! +``` + +## Next steps + +Experiment with the server - can you make it accept requests on other paths? + +What about query parameters or custom headers? + +> [!TIP] +> You can add `http-path` tuples to a multiaddr with: +> ``` +> addr.encapsulate(`/http-path/${encodeURIComponent(foo?bar=baz)}`) +> ``` + +How about making a request with a body such as a `POST` request? diff --git a/examples/websockets-over-libp2p/package.json b/examples/websockets-over-libp2p/package.json new file mode 100644 index 0000000..99ef103 --- /dev/null +++ b/examples/websockets-over-libp2p/package.json @@ -0,0 +1,33 @@ +{ + "name": "@libp2p/http-example-websockets-over-libp2p", + "version": "1.0.0", + "description": "How to serve WebSockets over libp2p streams", + "eslintConfig": { + "extends": "ipfs", + "parserOptions": { + "project": true, + "sourceType": "module" + } + }, + "scripts": { + "clean": "aegir clean", + "lint": "aegir lint", + "dep-check": "aegir dep-check", + "test": "test-node-example test/*" + }, + "dependencies": { + "@chainsafe/libp2p-noise": "^16.1.3", + "@chainsafe/libp2p-yamux": "^7.0.1", + "@libp2p/http": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "@libp2p/tcp": "^10.1.13", + "@multiformats/multiaddr": "^12.4.0", + "libp2p": "^2.8.8" + }, + "devDependencies": { + "aegir": "^47.0.16", + "test-ipfs-example": "^1.3.3" + }, + "private": true, + "type": "module" +} diff --git a/examples/websockets-over-libp2p/src/client.js b/examples/websockets-over-libp2p/src/client.js new file mode 100644 index 0000000..599235a --- /dev/null +++ b/examples/websockets-over-libp2p/src/client.js @@ -0,0 +1,60 @@ +/* eslint-disable no-console */ + +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { tcp } from '@libp2p/tcp' +import { multiaddr } from '@multiformats/multiaddr' +import { createLibp2p } from 'libp2p' + +// Take the first argument as the path of the folder to add +const args = process.argv.slice(2) + +// Example of how to use arguments +if (args.length === 0) { + console.error('No argument provided') + console.error('Usage: node client.js ') + process.exit(1) +} + +// turn the passed arg into a multiaddr +const addr = multiaddr(args[0]) + +const node = await createLibp2p({ + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http() + } +}) + +// make a HTTP request over libp2p +const socket = await node.services.http.connect(addr) + +if (socket.readyState !== WebSocket.OPEN) { + await new Promise((resolve, reject) => { + socket.addEventListener('open', () => { + resolve() + }, { + once: true + }) + socket.addEventListener('error', (evt) => { + reject(evt.error ?? new Error('Socket opening failed')) + }, { + once: true + }) + }) +} + +socket.addEventListener('message', (evt) => { + console.info('Incoming data:', new TextDecoder().decode(evt.data)) +}) + +socket.send('Hello World!') diff --git a/examples/websockets-over-libp2p/src/server.js b/examples/websockets-over-libp2p/src/server.js new file mode 100644 index 0000000..be38c6a --- /dev/null +++ b/examples/websockets-over-libp2p/src/server.js @@ -0,0 +1,63 @@ +/* eslint-disable no-console */ + +import { createServer } from 'node:http' +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http } from '@libp2p/http' +import { nodeServer } from '@libp2p/http-server' +import { createWebSocketServer } from '@libp2p/http-server/node' +import { tcp } from '@libp2p/tcp' +import { createLibp2p } from 'libp2p' + +// this express app is where any business logic necessary to server HTTP +// resources will take place +const wss = createWebSocketServer() +wss.addEventListener('connection', (evt) => { + const ws = evt.webSocket + + ws.addEventListener('message', (evt) => { + ws.send(evt.data) + }) +}) + +// this Node.js http.Server will receive incoming socket connections and convert +// them to HTTP requests - note that we don't need to call `server.listen` - +// libp2p will provide the networking layer +const server = createServer() +server.on('request', (req, res) => { + res.statusCode = 404 + res.end() +}) + +server.addListener('upgrade', (request, socket, head) => { + wss.handleUpgrade(request, socket, head) +}) + +// create a libp2p node that listens on a TCP address +const node = await createLibp2p({ + addresses: { + listen: [ + '/ip4/0.0.0.0/tcp/0' + ] + }, + transports: [ + tcp() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http({ + // allow injecting requests into the Node.js http.Server + server: nodeServer(server) + }) + } +}) + +console.info('Server listening on:') +node.getMultiaddrs().forEach(ma => { + console.info(ma.toString()) +}) diff --git a/examples/websockets-over-libp2p/test/index.spec.js b/examples/websockets-over-libp2p/test/index.spec.js new file mode 100644 index 0000000..1280ab6 --- /dev/null +++ b/examples/websockets-over-libp2p/test/index.spec.js @@ -0,0 +1,29 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { matchOutput } from 'test-ipfs-example/node' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +// Step 1 start server +process.stdout.write('node server.js\n') + +const { + process: server, + matches: addresses +} = await matchOutput(/Server listening on:\n(.*)\n/, 'node', [path.resolve(__dirname, '../src/server.js')]) + +const address = addresses.slice(1).map(line => line.trim()).pop() + +process.stdout.write('==================================================================\n') + +// Step 2 start client +process.stdout.write(`node client.js ${address}\n`) + +const { + process: client +} = await matchOutput(/Hello World!/g, 'node', [path.resolve(__dirname, '../src/client.js'), address]) + +process.stdout.write('==================================================================\n') + +client.kill() +server.kill() diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index d61ac74..0000000 --- a/package-lock.json +++ /dev/null @@ -1,25579 +0,0 @@ -{ - "name": "@libp2p/http-fetch", - "version": "2.2.2", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@libp2p/http-fetch", - "version": "2.2.2", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@achingbrain/http-parser-js": "^0.5.8", - "@libp2p/crypto": "^5.0.6", - "@libp2p/interface": "^2.2.0", - "@libp2p/interface-internal": "^2.0.10", - "@libp2p/peer-id": "^5.0.7", - "@multiformats/multiaddr": "^12.3.0", - "@multiformats/multiaddr-to-uri": "^11.0.0", - "http-cookie-agent": "^6.0.7", - "p-defer": "^4.0.1", - "tough-cookie": "^5.0.0", - "uint8-varint": "^2.0.4", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0", - "undici": "^6.21.0" - }, - "devDependencies": { - "@libp2p/interface-compliance-tests": "^6.1.8", - "@libp2p/logger": "^5.1.3", - "aegir": "^45.0.0", - "it-pair": "^2.0.6", - "libp2p": "^2.2.1", - "sinon-ts": "^2.0.0" - } - }, - "node_modules/@achingbrain/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/@achingbrain/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-7P8ukzL4jyh8Fho5tSfPBTzWJUZ0D7DxaW7ObObT5HTcljhjq9NN/qFg1yzPxq0VWRI/8qPnSUa1ofzzH/R9eQ==", - "license": "MIT", - "dependencies": { - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "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.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.26.8.tgz", - "integrity": "sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.10.tgz", - "integrity": "sha512-vMqyb7XCDMPvJFFOaT9kxtiRh42GwlZEg1/uIgtZshS5a/8OaduUfCi7kynKgc3Tw/6Uo2D+db9qBttghhmxwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.10", - "@babel/helper-compilation-targets": "^7.26.5", - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helpers": "^7.26.10", - "@babel/parser": "^7.26.10", - "@babel/template": "^7.26.9", - "@babel/traverse": "^7.26.10", - "@babel/types": "^7.26.10", - "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==", - "dev": true, - "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==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.0.tgz", - "integrity": "sha512-LVk7fbXml0H2xH34dFzKQ7TDZ2G4/rVTOrq9V+icbbadjbVxxeFeDsNHv2SrZeWoA+6ZiTyWYWtScEIW07EAcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.26.8", - "@babel/helper-validator-option": "^7.25.9", - "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==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz", - "integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.27.0", - "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.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.27.0.tgz", - "integrity": "sha512-fO8l08T76v48BhpNRW/nQ0MxfnSdoSKUJBMjubOAYffsVuGG5qOfMq7N6Es7UJvi7Y8goXXo07EfcHZXDPuELQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "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.4", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.4.tgz", - "integrity": "sha512-jljfR1rGnXXNWnmQg2K3+bvhkxB51Rl32QRaOTuwwjviGrHzIbSc8+x9CpraDtbT7mfyjXObULP4w/adunNwAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.22.6", - "@babel/helper-plugin-utils": "^7.22.5", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2" - }, - "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-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.9.tgz", - "integrity": "sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-wrap-function": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.26.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.25.9.tgz", - "integrity": "sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.25.9", - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz", - "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.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.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-default-from/-/plugin-proposal-export-default-from-7.25.9.tgz", - "integrity": "sha512-ykqgwNfSnNOB+C8fV5X4mG3AVmvu+WVxcaU9xHHtBb7PCrPeweMmPjGsn8eMaeJg6SJuoUuZENeeSWaarWqonQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.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.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-default-from/-/plugin-syntax-export-default-from-7.25.9.tgz", - "integrity": "sha512-9MhJ/SMTsVqsd69GyQg89lYR4o9T+oDGv5F6IsigxxqFVOyR/IflDLYP8WDI1l8fkhNGGktqkvL5qwNCtGEpgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-flow": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.26.0.tgz", - "integrity": "sha512-B+O2DnPc0iG+YXFqOxv2WNuNU97ToWjOomUQ78DouOENWUaM5sVrmet9mcomUGQFwpJd//gvUagXBSdzO1fRKg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.9.tgz", - "integrity": "sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.9.tgz", - "integrity": "sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.9.tgz", - "integrity": "sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.27.0.tgz", - "integrity": "sha512-u1jGphZ8uDI2Pj/HJj6YQ6XQLZCNjOlprjxB5SVz6rq2T6SwAR+CdrWK0CP7F+9rDVMXdB0+r6Am5G5aobOjAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.9.tgz", - "integrity": "sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-replace-supers": "^7.25.9", - "@babel/traverse": "^7.25.9", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.9.tgz", - "integrity": "sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/template": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.9.tgz", - "integrity": "sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.26.3.tgz", - "integrity": "sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.26.5.tgz", - "integrity": "sha512-eGK26RsbIkYUns3Y8qKl362juDDYK+wEdPGHGrhzUl6CewZFo55VZ7hg+CyMFU4dd5QQakBN86nBMpRsFpRvbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/plugin-syntax-flow": "^7.26.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.26.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.26.9.tgz", - "integrity": "sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.9.tgz", - "integrity": "sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/traverse": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.9.tgz", - "integrity": "sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-assign": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-assign/-/plugin-transform-object-assign-7.25.9.tgz", - "integrity": "sha512-I/Vl1aQnPsrrn837oLbo+VQtkNcjuuiATqwmuweg4fTauwHHQoxyjmjjOVKyO8OaTxgqYTKW3LuQsykXjDf5Ag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.9.tgz", - "integrity": "sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.9.tgz", - "integrity": "sha512-KJfMlYIUxQB1CJfO3e0+h0ZHWOTLCPP115Awhaz8U0Zpq36Gl/cXlpoyMRnUWlhNUBAzldnCiAZNvCDj7CrKxQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.9.tgz", - "integrity": "sha512-s5XwpQYCqGerXl+Pu6VDL3x0j2d82eiV77UJ8a2mDHAW7j9SWRqQ2y1fNo1Z74CdcYipl5Z41zvjj4Nfzq36rw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/plugin-syntax-jsx": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.25.9.tgz", - "integrity": "sha512-y8quW6p0WHkEhmErnfe58r7x0A70uKphQm8Sp8cV7tjNQwK56sNVK0M73LK3WuYmsuyrftut4xAkjjgU0twaMg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.25.9.tgz", - "integrity": "sha512-+iqjT8xmXhhYv4/uiYd8FNQsraMFZIfxVSqxxVSZP0WbbSAWvBXAul0m/zu+7Vv4O/3WtApy9pmaTMiumEZgfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.27.0.tgz", - "integrity": "sha512-LX/vCajUJQDqE7Aum/ELUMZAY19+cDpghxrnyt5I1tV6X5PyC86AOoWXWFYFeIvauyeSA6/ktn4tQVn/3ZifsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5", - "regenerator-transform": "^0.15.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-runtime": { - "version": "7.26.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.26.10.tgz", - "integrity": "sha512-NWaL2qG6HRpONTnj4JvDU6th4jYeZOJgu3QhmFTCihib0ermtOJqktA5BduGm3suhhVe9EMP9c9+mfJ/I9slqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-plugin-utils": "^7.26.5", - "babel-plugin-polyfill-corejs2": "^0.4.10", - "babel-plugin-polyfill-corejs3": "^0.11.0", - "babel-plugin-polyfill-regenerator": "^0.6.1", - "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.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.9.tgz", - "integrity": "sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.9.tgz", - "integrity": "sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.9.tgz", - "integrity": "sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.26.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.26.8.tgz", - "integrity": "sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.26.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typescript": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.27.0.tgz", - "integrity": "sha512-fRGGjO2UEGPjvEcyAZXRXAS8AfdaQoq7HnxAbJoAoW10B9xOKesmmndJv+Sym2a+9FHWZ9KbyyLCe9s0Sn5jtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-create-class-features-plugin": "^7.27.0", - "@babel/helper-plugin-utils": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/plugin-syntax-typescript": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.9.tgz", - "integrity": "sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.25.9", - "@babel/helper-plugin-utils": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "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/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/@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": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.17.5.tgz", - "integrity": "sha512-b/Ntabar+g4gsRNwOct909cvatO/auHhNvBzJZfyFQzryI1nqHMaSFuDsrrtzbhQkGJ4GiMAKCXZC2EOdHMgmw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-ada": "^4.1.0", - "@cspell/dict-al": "^1.1.0", - "@cspell/dict-aws": "^4.0.9", - "@cspell/dict-bash": "^4.2.0", - "@cspell/dict-companies": "^3.1.14", - "@cspell/dict-cpp": "^6.0.4", - "@cspell/dict-cryptocurrencies": "^5.0.4", - "@cspell/dict-csharp": "^4.0.6", - "@cspell/dict-css": "^4.0.17", - "@cspell/dict-dart": "^2.3.0", - "@cspell/dict-data-science": "^2.0.7", - "@cspell/dict-django": "^4.1.4", - "@cspell/dict-docker": "^1.1.12", - "@cspell/dict-dotnet": "^5.0.9", - "@cspell/dict-elixir": "^4.0.7", - "@cspell/dict-en_us": "^4.3.33", - "@cspell/dict-en-common-misspellings": "^2.0.9", - "@cspell/dict-en-gb": "1.1.33", - "@cspell/dict-filetypes": "^3.0.11", - "@cspell/dict-flutter": "^1.1.0", - "@cspell/dict-fonts": "^4.0.4", - "@cspell/dict-fsharp": "^1.1.0", - "@cspell/dict-fullstack": "^3.2.5", - "@cspell/dict-gaming-terms": "^1.1.0", - "@cspell/dict-git": "^3.0.4", - "@cspell/dict-golang": "^6.0.18", - "@cspell/dict-google": "^1.0.8", - "@cspell/dict-haskell": "^4.0.5", - "@cspell/dict-html": "^4.0.11", - "@cspell/dict-html-symbol-entities": "^4.0.3", - "@cspell/dict-java": "^5.0.11", - "@cspell/dict-julia": "^1.1.0", - "@cspell/dict-k8s": "^1.0.10", - "@cspell/dict-kotlin": "^1.1.0", - "@cspell/dict-latex": "^4.0.3", - "@cspell/dict-lorem-ipsum": "^4.0.4", - "@cspell/dict-lua": "^4.0.7", - "@cspell/dict-makefile": "^1.0.4", - "@cspell/dict-markdown": "^2.0.9", - "@cspell/dict-monkeyc": "^1.0.10", - "@cspell/dict-node": "^5.0.6", - "@cspell/dict-npm": "^5.1.27", - "@cspell/dict-php": "^4.0.14", - "@cspell/dict-powershell": "^5.0.14", - "@cspell/dict-public-licenses": "^2.0.13", - "@cspell/dict-python": "^4.2.15", - "@cspell/dict-r": "^2.1.0", - "@cspell/dict-ruby": "^5.0.7", - "@cspell/dict-rust": "^4.0.11", - "@cspell/dict-scala": "^5.0.7", - "@cspell/dict-shell": "^1.1.0", - "@cspell/dict-software-terms": "^4.2.5", - "@cspell/dict-sql": "^2.2.0", - "@cspell/dict-svelte": "^1.0.6", - "@cspell/dict-swift": "^2.0.5", - "@cspell/dict-terraform": "^1.1.0", - "@cspell/dict-typescript": "^3.2.0", - "@cspell/dict-vue": "^3.0.4" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/cspell-json-reporter": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.17.5.tgz", - "integrity": "sha512-+eVFCdnda74Frv8hguHYwDtxvqDuJJ/luFRl4dC5oknPMRab0JCHM1DDYjp3NzsehTex0HmcxplxqVW6QoDosg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-types": "8.17.5" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/cspell-pipe": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.17.5.tgz", - "integrity": "sha512-VOIfFdIo3FYQFcSpIyGkqHupOx0LgfBrWs79IKnTT1II27VUHPF+0oGq0WWf4c2Zpd8tzdHvS3IUhGarWZq69g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/cspell-resolver": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.17.5.tgz", - "integrity": "sha512-5MhYInligPbGctWxoklAKxtg+sxvtJCuRKGSQHHA0JlCOLSsducypl780P6zvpjLK59XmdfC+wtFONxSmRbsuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "global-directory": "^4.0.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/cspell-service-bus": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.17.5.tgz", - "integrity": "sha512-Ur3IK0R92G/2J6roopG9cU/EhoYAMOx2um7KYlq93cdrly8RBAK2NCcGCL7DbjQB6C9RYEAV60ueMUnQ45RrCQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/cspell-types": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.17.5.tgz", - "integrity": "sha512-91y2+0teunRSRZj940ORDA3kdjyenrUiM+4j6nQQH24sAIAJdRmQl2LG3eUTmeaSReJGkZIpnToQ6DyU5cC88Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/dict-ada": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.0.tgz", - "integrity": "sha512-7SvmhmX170gyPd+uHXrfmqJBY5qLcCX8kTGURPVeGxmt8XNXT75uu9rnZO+jwrfuU2EimNoArdVy5GZRGljGNg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-al": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.0.tgz", - "integrity": "sha512-PtNI1KLmYkELYltbzuoztBxfi11jcE9HXBHCpID2lou/J4VMYKJPNqe4ZjVzSI9NYbMnMnyG3gkbhIdx66VSXg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-aws": { - "version": "4.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.9.tgz", - "integrity": "sha512-bDYdnnJGwSkIZ4gzrauu7qzOs/ZAY/FnU4k11LgdMI8BhwMfsbsy2EI1iS+sD/BI5ZnNT9kU5YR3WADeNOmhRg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-bash": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.0.tgz", - "integrity": "sha512-HOyOS+4AbCArZHs/wMxX/apRkjxg6NDWdt0jF9i9XkvJQUltMwEhyA2TWYjQ0kssBsnof+9amax2lhiZnh3kCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-shell": "1.1.0" - } - }, - "node_modules/@cspell/dict-companies": { - "version": "3.1.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.1.14.tgz", - "integrity": "sha512-iqo1Ce4L7h0l0GFSicm2wCLtfuymwkvgFGhmu9UHyuIcTbdFkDErH+m6lH3Ed+QuskJlpQ9dM7puMIGqUlVERw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cpp": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-6.0.6.tgz", - "integrity": "sha512-HMV1chsExuZt5IL9rYBW7GmhNZDVdQJEd1WtFgOO6jqiNxbpTG3Is3Pkldl7FpusBQQZr4BdjMit5bnPpVRy3A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-cryptocurrencies": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.4.tgz", - "integrity": "sha512-6iFu7Abu+4Mgqq08YhTKHfH59mpMpGTwdzDB2Y8bbgiwnGFCeoiSkVkgLn1Kel2++hYcZ8vsAW/MJS9oXxuMag==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-csharp": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.6.tgz", - "integrity": "sha512-w/+YsqOknjQXmIlWDRmkW+BHBPJZ/XDrfJhZRQnp0wzpPOGml7W0q1iae65P2AFRtTdPKYmvSz7AL5ZRkCnSIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-css": { - "version": "4.0.17", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.17.tgz", - "integrity": "sha512-2EisRLHk6X/PdicybwlajLGKF5aJf4xnX2uuG5lexuYKt05xV/J/OiBADmi8q9obhxf1nesrMQbqAt+6CsHo/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-dart": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.0.tgz", - "integrity": "sha512-1aY90lAicek8vYczGPDKr70pQSTQHwMFLbmWKTAI6iavmb1fisJBS1oTmMOKE4ximDf86MvVN6Ucwx3u/8HqLg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-data-science": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.7.tgz", - "integrity": "sha512-XhAkK+nSW6zmrnWzusmZ1BpYLc62AWYHZc2p17u4nE2Z9XG5DleG55PCZxXQTKz90pmwlhFM9AfpkJsYaBWATA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-django": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.4.tgz", - "integrity": "sha512-fX38eUoPvytZ/2GA+g4bbdUtCMGNFSLbdJJPKX2vbewIQGfgSFJKY56vvcHJKAvw7FopjvgyS/98Ta9WN1gckg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-docker": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.12.tgz", - "integrity": "sha512-6d25ZPBnYZaT9D9An/x6g/4mk542R8bR3ipnby3QFCxnfdd6xaWiTcwDPsCgwN2aQZIQ1jX/fil9KmBEqIK/qA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-dotnet": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.9.tgz", - "integrity": "sha512-JGD6RJW5sHtO5lfiJl11a5DpPN6eKSz5M1YBa1I76j4dDOIqgZB6rQexlDlK1DH9B06X4GdDQwdBfnpAB0r2uQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-elixir": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.7.tgz", - "integrity": "sha512-MAUqlMw73mgtSdxvbAvyRlvc3bYnrDqXQrx5K9SwW8F7fRYf9V4vWYFULh+UWwwkqkhX9w03ZqFYRTdkFku6uA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-en_us": { - "version": "4.3.35", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.3.35.tgz", - "integrity": "sha512-HF6QNyPHkxeo/SosaZXRQlnKDUTjIzrGKyqfbw/fPPlPYrXefAZZ40ofheb5HnbUicR7xqV/lsc/HQfqYshGIw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-en-common-misspellings": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.0.10.tgz", - "integrity": "sha512-80mXJLtr0tVEtzowrI7ycVae/ULAYImZUlr0kUTpa8i57AUk7Zy3pYBs44EYIKW7ZC9AHu4Qjjfq4vriAtyTDQ==", - "dev": true, - "license": "CC BY-SA 4.0" - }, - "node_modules/@cspell/dict-en-gb": { - "version": "1.1.33", - "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", - "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-filetypes": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.11.tgz", - "integrity": "sha512-bBtCHZLo7MiSRUqx5KEiPdGOmXIlDGY+L7SJEtRWZENpAKE+96rT7hj+TUUYWBbCzheqHr0OXZJFEKDgsG/uZg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-flutter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.0.tgz", - "integrity": "sha512-3zDeS7zc2p8tr9YH9tfbOEYfopKY/srNsAa+kE3rfBTtQERAZeOhe5yxrnTPoufctXLyuUtcGMUTpxr3dO0iaA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fonts": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.4.tgz", - "integrity": "sha512-cHFho4hjojBcHl6qxidl9CvUb492IuSk7xIf2G2wJzcHwGaCFa2o3gRcxmIg1j62guetAeDDFELizDaJlVRIOg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fsharp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.0.tgz", - "integrity": "sha512-oguWmHhGzgbgbEIBKtgKPrFSVAFtvGHaQS0oj+vacZqMObwkapcTGu7iwf4V3Bc2T3caf0QE6f6rQfIJFIAVsw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-fullstack": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.6.tgz", - "integrity": "sha512-cSaq9rz5RIU9j+0jcF2vnKPTQjxGXclntmoNp4XB7yFX2621PxJcekGjwf/lN5heJwVxGLL9toR0CBlGKwQBgA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-gaming-terms": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.0.tgz", - "integrity": "sha512-46AnDs9XkgJ2f1Sqol1WgfJ8gOqp60fojpc9Wxch7x+BA63g4JfMV5/M5x0sI0TLlLY8EBSglcr8wQF/7C80AQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-git": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.0.4.tgz", - "integrity": "sha512-C44M+m56rYn6QCsLbiKiedyPTMZxlDdEYAsPwwlL5bhMDDzXZ3Ic8OCQIhMbiunhCOJJT+er4URmOmM+sllnjg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-golang": { - "version": "6.0.19", - "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.19.tgz", - "integrity": "sha512-VS+oinB2/CbgmHE06kMJlj52OVMZM0S2EEXph3oaroNTgTuclSwdFylQmOEjquZi55kW+n3FM9MyWXiitB7Dtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-google": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.8.tgz", - "integrity": "sha512-BnMHgcEeaLyloPmBs8phCqprI+4r2Jb8rni011A8hE+7FNk7FmLE3kiwxLFrcZnnb7eqM0agW4zUaNoB0P+z8A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-haskell": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.5.tgz", - "integrity": "sha512-s4BG/4tlj2pPM9Ha7IZYMhUujXDnI0Eq1+38UTTCpatYLbQqDwRFf2KNPLRqkroU+a44yTUAe0rkkKbwy4yRtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-html": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.11.tgz", - "integrity": "sha512-QR3b/PB972SRQ2xICR1Nw/M44IJ6rjypwzA4jn+GH8ydjAX9acFNfc+hLZVyNe0FqsE90Gw3evLCOIF0vy1vQw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-html-symbol-entities": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.3.tgz", - "integrity": "sha512-aABXX7dMLNFdSE8aY844X4+hvfK7977sOWgZXo4MTGAmOzR8524fjbJPswIBK7GaD3+SgFZ2yP2o0CFvXDGF+A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-java": { - "version": "5.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.11.tgz", - "integrity": "sha512-T4t/1JqeH33Raa/QK/eQe26FE17eUCtWu+JsYcTLkQTci2dk1DfcIKo8YVHvZXBnuM43ATns9Xs0s+AlqDeH7w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-julia": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.0.tgz", - "integrity": "sha512-CPUiesiXwy3HRoBR3joUseTZ9giFPCydSKu2rkh6I2nVjXnl5vFHzOMLXpbF4HQ1tH2CNfnDbUndxD+I+7eL9w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-k8s": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.10.tgz", - "integrity": "sha512-313haTrX9prep1yWO7N6Xw4D6tvUJ0Xsx+YhCP+5YrrcIKoEw5Rtlg8R4PPzLqe6zibw6aJ+Eqq+y76Vx5BZkw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-kotlin": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.0.tgz", - "integrity": "sha512-vySaVw6atY7LdwvstQowSbdxjXG6jDhjkWVWSjg1XsUckyzH1JRHXe9VahZz1i7dpoFEUOWQrhIe5B9482UyJQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-latex": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-4.0.3.tgz", - "integrity": "sha512-2KXBt9fSpymYHxHfvhUpjUFyzrmN4c4P8mwIzweLyvqntBT3k0YGZJSriOdjfUjwSygrfEwiuPI1EMrvgrOMJw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-lorem-ipsum": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.4.tgz", - "integrity": "sha512-+4f7vtY4dp2b9N5fn0za/UR0kwFq2zDtA62JCbWHbpjvO9wukkbl4rZg4YudHbBgkl73HRnXFgCiwNhdIA1JPw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-lua": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.7.tgz", - "integrity": "sha512-Wbr7YSQw+cLHhTYTKV6cAljgMgcY+EUAxVIZW3ljKswEe4OLxnVJ7lPqZF5JKjlXdgCjbPSimsHqyAbC5pQN/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-makefile": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.4.tgz", - "integrity": "sha512-E4hG/c0ekPqUBvlkrVvzSoAA+SsDA9bLi4xSV3AXHTVru7Y2bVVGMPtpfF+fI3zTkww/jwinprcU1LSohI3ylw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-markdown": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.9.tgz", - "integrity": "sha512-j2e6Eg18BlTb1mMP1DkyRFMM/FLS7qiZjltpURzDckB57zDZbUyskOFdl4VX7jItZZEeY0fe22bSPOycgS1Z5A==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@cspell/dict-css": "^4.0.17", - "@cspell/dict-html": "^4.0.11", - "@cspell/dict-html-symbol-entities": "^4.0.3", - "@cspell/dict-typescript": "^3.2.0" - } - }, - "node_modules/@cspell/dict-monkeyc": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.10.tgz", - "integrity": "sha512-7RTGyKsTIIVqzbvOtAu6Z/lwwxjGRtY5RkKPlXKHEoEAgIXwfDxb5EkVwzGQwQr8hF/D3HrdYbRT8MFBfsueZw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-node": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.6.tgz", - "integrity": "sha512-CEbhPCpxGvRNByGolSBTrXXW2rJA4bGqZuTx1KKO85mwR6aadeOmUE7xf/8jiCkXSy+qvr9aJeh+jlfXcsrziQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-npm": { - "version": "5.1.31", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.1.31.tgz", - "integrity": "sha512-Oh9nrhgNV4UD1hlbgO3TFQqQRKziwc7qXKoQiC4oqOYIhMs2WL9Ezozku7FY1e7o5XbCIZX9nRH0ymNx/Rwj6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-php": { - "version": "4.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.0.14.tgz", - "integrity": "sha512-7zur8pyncYZglxNmqsRycOZ6inpDoVd4yFfz1pQRe5xaRWMiK3Km4n0/X/1YMWhh3e3Sl/fQg5Axb2hlN68t1g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-powershell": { - "version": "5.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.14.tgz", - "integrity": "sha512-ktjjvtkIUIYmj/SoGBYbr3/+CsRGNXGpvVANrY0wlm/IoGlGywhoTUDYN0IsGwI2b8Vktx3DZmQkfb3Wo38jBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-public-licenses": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.13.tgz", - "integrity": "sha512-1Wdp/XH1ieim7CadXYE7YLnUlW0pULEjVl9WEeziZw3EKCAw8ZI8Ih44m4bEa5VNBLnuP5TfqC4iDautAleQzQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-python": { - "version": "4.2.16", - "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.16.tgz", - "integrity": "sha512-LkQssFt1hPOWXIQiD8ScTkz/41RL7Ti0V/2ytUzEW82dc0atIEksrBg8MuOjWXktp0Dk5tDwRLgmIvhV3CFFOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/dict-data-science": "^2.0.7" - } - }, - "node_modules/@cspell/dict-r": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.0.tgz", - "integrity": "sha512-k2512wgGG0lTpTYH9w5Wwco+lAMf3Vz7mhqV8+OnalIE7muA0RSuD9tWBjiqLcX8zPvEJr4LdgxVju8Gk3OKyA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-ruby": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.0.8.tgz", - "integrity": "sha512-ixuTneU0aH1cPQRbWJvtvOntMFfeQR2KxT8LuAv5jBKqQWIHSxzGlp+zX3SVyoeR0kOWiu64/O5Yn836A5yMcQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-rust": { - "version": "4.0.11", - "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.11.tgz", - "integrity": "sha512-OGWDEEzm8HlkSmtD8fV3pEcO2XBpzG2XYjgMCJCRwb2gRKvR+XIm6Dlhs04N/K2kU+iH8bvrqNpM8fS/BFl0uw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-scala": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.7.tgz", - "integrity": "sha512-yatpSDW/GwulzO3t7hB5peoWwzo+Y3qTc0pO24Jf6f88jsEeKmDeKkfgPbYuCgbE4jisGR4vs4+jfQZDIYmXPA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-shell": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.1.0.tgz", - "integrity": "sha512-D/xHXX7T37BJxNRf5JJHsvziFDvh23IF/KvkZXNSh8VqcRdod3BAz9VGHZf6VDqcZXr1VRqIYR3mQ8DSvs3AVQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-software-terms": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.2.5.tgz", - "integrity": "sha512-CaRzkWti3AgcXoxuRcMijaNG7YUk/MH1rHjB8VX34v3UdCxXXeqvRyElRKnxhFeVLB/robb2UdShqh/CpskxRg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-sql": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.0.tgz", - "integrity": "sha512-MUop+d1AHSzXpBvQgQkCiok8Ejzb+nrzyG16E8TvKL2MQeDwnIvMe3bv90eukP6E1HWb+V/MA/4pnq0pcJWKqQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-svelte": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.6.tgz", - "integrity": "sha512-8LAJHSBdwHCoKCSy72PXXzz7ulGROD0rP1CQ0StOqXOOlTUeSFaJJlxNYjlONgd2c62XBQiN2wgLhtPN+1Zv7Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-swift": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.5.tgz", - "integrity": "sha512-3lGzDCwUmnrfckv3Q4eVSW3sK3cHqqHlPprFJZD4nAqt23ot7fic5ALR7J4joHpvDz36nHX34TgcbZNNZOC/JA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-terraform": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.1.tgz", - "integrity": "sha512-07KFDwCU7EnKl4hOZLsLKlj6Zceq/IsQ3LRWUyIjvGFfZHdoGtFdCp3ZPVgnFaAcd/DKv+WVkrOzUBSYqHopQQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-typescript": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.0.tgz", - "integrity": "sha512-Pk3zNePLT8qg51l0M4g1ISowYAEGxTuNfZlgkU5SvHa9Cu7x/BWoyYq9Fvc3kAyoisCjRPyvWF4uRYrPitPDFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dict-vue": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.4.tgz", - "integrity": "sha512-0dPtI0lwHcAgSiQFx8CzvqjdoXROcH+1LyqgROCpBgppommWpVhbQ0eubnKotFEXgpUCONVkeZJ6Ql8NbTEu+w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@cspell/dynamic-import": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.17.5.tgz", - "integrity": "sha512-tY+cVkRou+0VKvH+K1NXv8/R7mOlW3BDGSs9fcgvhatj0m00Yf8blFC7tE4VVI9Qh2bkC/KDFqM24IqZbuwXUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "8.17.5", - "import-meta-resolve": "^4.1.0" - }, - "engines": { - "node": ">=18.0" - } - }, - "node_modules/@cspell/filetypes": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-8.17.5.tgz", - "integrity": "sha512-Fj6py2Rl+FEnMiXhRQUM1A5QmyeCLxi6dY/vQ0qfH6tp6KSaBiaC8wuPUKhr8hKyTd3+8lkUbobDhUf6xtMEXg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/strong-weak-map": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.17.5.tgz", - "integrity": "sha512-Z4eo+rZJr1086wZWycBiIG/n7gGvVoqn28I7ZicS8xedRYu/4yp2loHgLn4NpxG3e46+dNWs4La6vinod+UydQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@cspell/url": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/@cspell/url/-/url-8.17.5.tgz", - "integrity": "sha512-GNQqST7zI85dAFVyao6oiTeg5rNhO9FH1ZAd397qQhvwfxrrniNfuoewu8gPXyP0R4XBiiaCwhBL7w9S/F5guw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0" - } - }, - "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": "3.1.0", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-3.1.0.tgz", - "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "env-paths": "^2.2.0", - "fs-extra": "^8.1.0", - "got": "^11.8.5", - "progress": "^2.0.3", - "semver": "^6.2.0", - "sumchecker": "^3.0.1" - }, - "engines": { - "node": ">=14" - }, - "optionalDependencies": { - "global-agent": "^3.0.0" - } - }, - "node_modules/@electron/get/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/@electron/get/node_modules/fs-extra": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", - "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/@electron/get/node_modules/jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/get/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/@electron/get/node_modules/universalify": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", - "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.46.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.46.0.tgz", - "integrity": "sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "comment-parser": "1.4.1", - "esquery": "^1.6.0", - "jsdoc-type-pratt-parser": "~4.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", - "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", - "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", - "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", - "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", - "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", - "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", - "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", - "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", - "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", - "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", - "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", - "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", - "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", - "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", - "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", - "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", - "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", - "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", - "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", - "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", - "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", - "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", - "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", - "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", - "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", - "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", - "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/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/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.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.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/eslintrc/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/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/@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/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "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/@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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "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": { - "version": "5.0.15", - "resolved": "https://registry.npmjs.org/@libp2p/crypto/-/crypto-5.0.15.tgz", - "integrity": "sha512-28xYMOn3fs8flsNgCVVxp27gEmDTtZHbz+qEVv3v7cWfGRipaVhNXFV9tQJHWXHQ8mN8v/PQvgcfCcWu5jkrTg==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.7.0", - "@noble/curves": "^1.7.0", - "@noble/hashes": "^1.6.1", - "multiformats": "^13.3.1", - "protons-runtime": "^5.5.0", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@libp2p/echo": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/@libp2p/echo/-/echo-2.1.18.tgz", - "integrity": "sha512-EBUgi7XPPeHDTLp4VlttzesIi4MbVxFq0uDYiBkLyjqsqxjKsrYwmUw9aakbWsujpN+fGp8TtAm+NeQw/Xmtcg==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.7.0", - "@libp2p/interface-internal": "^2.3.9", - "@multiformats/multiaddr": "^12.3.3", - "it-byte-stream": "^1.1.0", - "it-pipe": "^3.0.1" - } - }, - "node_modules/@libp2p/interface": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/@libp2p/interface/-/interface-2.7.0.tgz", - "integrity": "sha512-lWmfIGzbSaw//yoEWWJh8dXNDGSCwUyXwC7P1Q6jCFWNoEtCaB1pvwOGBtri7Db/aNFZryMzN5covoq5ulldnA==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.3.3", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.2", - "multiformats": "^13.3.1", - "progress-events": "^1.0.1", - "uint8arraylist": "^2.4.8" - } - }, - "node_modules/@libp2p/interface-compliance-tests": { - "version": "6.4.2", - "resolved": "https://registry.npmjs.org/@libp2p/interface-compliance-tests/-/interface-compliance-tests-6.4.2.tgz", - "integrity": "sha512-LsiOEFKvw4bIyQOC2kdbKP8/+7QoZBXR0Se45EM9YBDPWWnHnLxbRzGfqZRI3xL+WfG7vtEU4suqTk9cjr6efQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.15", - "@libp2p/echo": "^2.1.18", - "@libp2p/interface": "^2.7.0", - "@libp2p/interface-internal": "^2.3.9", - "@libp2p/logger": "^5.1.13", - "@libp2p/memory": "^1.1.4", - "@libp2p/multistream-select": "^6.0.20", - "@libp2p/peer-collections": "^6.0.25", - "@libp2p/peer-id": "^5.1.0", - "@libp2p/plaintext": "^2.0.20", - "@libp2p/utils": "^6.6.0", - "@multiformats/multiaddr": "^12.3.3", - "@multiformats/multiaddr-matcher": "^1.6.0", - "abortable-iterator": "^5.1.0", - "aegir": "^45.1.1", - "any-signal": "^4.1.1", - "delay": "^6.0.0", - "it-all": "^3.0.6", - "it-byte-stream": "^1.1.0", - "it-drain": "^3.0.7", - "it-map": "^3.1.1", - "it-ndjson": "^1.0.7", - "it-pair": "^2.0.6", - "it-pipe": "^3.0.1", - "it-protobuf-stream": "^1.1.5", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.2", - "it-to-buffer": "^4.0.7", - "libp2p": "^2.8.2", - "merge-options": "^3.0.4", - "p-defer": "^4.0.1", - "p-event": "^6.0.1", - "p-limit": "^6.1.0", - "p-retry": "^6.2.1", - "p-wait-for": "^5.0.2", - "protons-runtime": "^5.5.0", - "race-signal": "^1.1.0", - "sinon": "^19.0.2", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@libp2p/interface-compliance-tests/node_modules/sinon": { - "version": "19.0.5", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-19.0.5.tgz", - "integrity": "sha512-r15s9/s+ub/d4bxNXqIUmwp6imVSdTorIRaxoecYjqTVLZ8RuoXr/4EDGwIBo6Waxn7f2gnURX9zuhAfCwaF6Q==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^13.0.5", - "@sinonjs/samsam": "^8.0.1", - "diff": "^7.0.0", - "nise": "^6.1.1", - "supports-color": "^7.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/@libp2p/interface-internal": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@libp2p/interface-internal/-/interface-internal-2.3.9.tgz", - "integrity": "sha512-1hW/yHktO3txc+r4ASmVA9GbNN6ZoGnH8Bt9VrYwY580BT53TP3eipn3Bo1XyGBDtmV6bpQiKhFK5AYVbhnz0g==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.7.0", - "@libp2p/peer-collections": "^6.0.25", - "@multiformats/multiaddr": "^12.3.3", - "progress-events": "^1.0.1" - } - }, - "node_modules/@libp2p/logger": { - "version": "5.1.13", - "resolved": "https://registry.npmjs.org/@libp2p/logger/-/logger-5.1.13.tgz", - "integrity": "sha512-JKyMlySG8T+LpItsj9Vma57yap/A0HqJ8ZdaHvgdoThhSOfqcRs8oRWO/2EG0Q5hUXugw//EAT+Ptj8MyNdbjQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.7.0", - "@multiformats/multiaddr": "^12.3.3", - "interface-datastore": "^8.3.1", - "multiformats": "^13.3.1", - "weald": "^1.0.4" - } - }, - "node_modules/@libp2p/memory": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@libp2p/memory/-/memory-1.1.4.tgz", - "integrity": "sha512-DOSrdjsZMiRrYcOMlfDWeH8ln5/9SpURUe3h5XP17O+Ojcer4eQu8sRm9csS47xoaOyrmurMhmrdovZS93G54g==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.7.0", - "@multiformats/multiaddr": "^12.3.3", - "@multiformats/multiaddr-matcher": "^1.6.0", - "@types/sinon": "^17.0.3", - "delay": "^6.0.0", - "it-map": "^3.1.1", - "it-pushable": "^3.2.3", - "nanoid": "^5.0.9", - "race-signal": "^1.1.3", - "uint8arraylist": "^2.4.8" - } - }, - "node_modules/@libp2p/multistream-select": { - "version": "6.0.20", - "resolved": "https://registry.npmjs.org/@libp2p/multistream-select/-/multistream-select-6.0.20.tgz", - "integrity": "sha512-DHObPodBZXNUFiMzMX0KSnkbDM6am4G8GfkfYPpmx+yuleuutiJrmN95Xt9ximhn9m+YtEZWB2Je8+Lb0bwIYQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.7.0", - "it-length-prefixed": "^10.0.1", - "it-length-prefixed-stream": "^1.2.0", - "it-stream-types": "^2.0.2", - "p-defer": "^4.0.1", - "race-signal": "^1.1.2", - "uint8-varint": "^2.0.4", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@libp2p/peer-collections": { - "version": "6.0.25", - "resolved": "https://registry.npmjs.org/@libp2p/peer-collections/-/peer-collections-6.0.25.tgz", - "integrity": "sha512-sU6mjwANQvVPgTgslRZvxZ6cYzQJ66QmNHm6mrM0cx03Yf1heWnvL28N/P781nGsUjo1cJD7xB5ctAGk6A/lXw==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/interface": "^2.7.0", - "@libp2p/peer-id": "^5.1.0", - "@libp2p/utils": "^6.6.0", - "multiformats": "^13.3.1" - } - }, - "node_modules/@libp2p/peer-id": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@libp2p/peer-id/-/peer-id-5.1.0.tgz", - "integrity": "sha512-9Xob9DDg1uBboM2QvJ5nyPbsjxsNS9obmGAYeAtLSx5aHAIC4AweJQFHssUUCfW7mufkzX/s3zyR62XPR4SYyQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.15", - "@libp2p/interface": "^2.7.0", - "multiformats": "^13.3.1", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@libp2p/peer-record": { - "version": "8.0.25", - "resolved": "https://registry.npmjs.org/@libp2p/peer-record/-/peer-record-8.0.25.tgz", - "integrity": "sha512-IFuAhxzMS/NlXZS7+vn7tTJY32ODtKN/aFBRd1wekAw5DebGtvqkt9mN3UbeXJPesu9w87e4Q8GSarD0URXRlw==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.15", - "@libp2p/interface": "^2.7.0", - "@libp2p/peer-id": "^5.1.0", - "@libp2p/utils": "^6.6.0", - "@multiformats/multiaddr": "^12.3.3", - "multiformats": "^13.3.1", - "protons-runtime": "^5.5.0", - "uint8-varint": "^2.0.4", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@libp2p/peer-store": { - "version": "11.1.2", - "resolved": "https://registry.npmjs.org/@libp2p/peer-store/-/peer-store-11.1.2.tgz", - "integrity": "sha512-2egfDs6j+uvreBrzChf5xwNe0kQgYhuaOBx3rVgCAHxuJyXK6/lK+PpEH3Cfgad+if388mII58MU5gzpbawsaw==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.15", - "@libp2p/interface": "^2.7.0", - "@libp2p/peer-id": "^5.1.0", - "@libp2p/peer-record": "^8.0.25", - "@multiformats/multiaddr": "^12.3.3", - "interface-datastore": "^8.3.1", - "it-all": "^3.0.6", - "mortice": "^3.0.6", - "multiformats": "^13.3.1", - "protons-runtime": "^5.5.0", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@libp2p/plaintext": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/@libp2p/plaintext/-/plaintext-2.0.20.tgz", - "integrity": "sha512-nkmoELzjaLisOZ4ok3PUyj+RuJUhD+9Chp9fOENpdEFiFDex9mqH62tZ5Hw1ZKrN4F3jDMY9pDbQk0yHS3MlwA==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/crypto": "^5.0.15", - "@libp2p/interface": "^2.7.0", - "@libp2p/peer-id": "^5.1.0", - "it-protobuf-stream": "^1.1.5", - "it-stream-types": "^2.0.2", - "protons-runtime": "^5.5.0", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/@libp2p/utils": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/@libp2p/utils/-/utils-6.6.0.tgz", - "integrity": "sha512-QjS1+r+jInOxULjdATBc1N/gorUWUoJqEKxpqTcB2wOwCipzB58RYR3n3QPeoRHj1mVMhZujE1dTbmK/Nafhqg==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.2", - "@chainsafe/netmask": "^2.0.0", - "@libp2p/crypto": "^5.0.15", - "@libp2p/interface": "^2.7.0", - "@libp2p/logger": "^5.1.13", - "@multiformats/multiaddr": "^12.3.3", - "@sindresorhus/fnv1a": "^3.1.0", - "any-signal": "^4.1.1", - "delay": "^6.0.0", - "get-iterator": "^2.0.1", - "is-loopback-addr": "^2.0.2", - "it-foreach": "^2.1.1", - "it-pipe": "^3.0.1", - "it-pushable": "^3.2.3", - "it-stream-types": "^2.0.2", - "netmask": "^2.0.2", - "p-defer": "^4.0.1", - "race-event": "^1.3.0", - "race-signal": "^1.1.2", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0" - } - }, - "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.4.0", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr/-/multiaddr-12.4.0.tgz", - "integrity": "sha512-FL7yBTLijJ5JkO044BGb2msf+uJLrwpD6jD6TkXlbjA9N12+18HT40jvd4o5vL4LOJMc86dPX6tGtk/uI9kYKg==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@chainsafe/netmask": "^2.0.0", - "@multiformats/dns": "^1.0.3", - "multiformats": "^13.0.0", - "uint8-varint": "^2.0.1", - "uint8arrays": "^5.0.0" - } - }, - "node_modules/@multiformats/multiaddr-matcher": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-matcher/-/multiaddr-matcher-1.6.0.tgz", - "integrity": "sha512-E77lLvQR+50kTAfvjV3g4wr9qCu77Z+6yT0s1hgfh8B4sAXZ8u/YdQJGhjgstgW1kmGy7BXPppROKYijqQsesQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.1", - "@multiformats/multiaddr": "^12.0.0", - "multiformats": "^13.0.0" - } - }, - "node_modules/@multiformats/multiaddr-to-uri": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/@multiformats/multiaddr-to-uri/-/multiaddr-to-uri-11.0.0.tgz", - "integrity": "sha512-9RNmlIGwZbBLsHekT50dbt4o4u8Iciw9kGjv+WHiGxQdsJ6xKKjU1+C0Vbas6RilMbaVOAOnEyfNcXbUmTkLxQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@multiformats/multiaddr": "^12.3.0" - } - }, - "node_modules/@noble/curves": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.1.tgz", - "integrity": "sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.7.1" - }, - "engines": { - "node": "^14.21.3 || >=16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@noble/hashes": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.1.tgz", - "integrity": "sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==", - "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/@octokit/auth-token": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-5.1.2.tgz", - "integrity": "sha512-JcQDsBdg49Yky2w2ld20IHAlwr8d/d8N6NiOXbtuoPCqzbsiJgF633mVUw3x4mo0H5ypataQIX7SFu3yy44Mpw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/core": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@octokit/core/-/core-6.1.4.tgz", - "integrity": "sha512-lAS9k7d6I0MPN+gb9bKDt7X8SdxknYqAMh44S5L+lNqIN2NuV8nvv3g8rPp7MuRxcOpxpUIATWprO0C34a8Qmg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/auth-token": "^5.0.0", - "@octokit/graphql": "^8.1.2", - "@octokit/request": "^9.2.1", - "@octokit/request-error": "^6.1.7", - "@octokit/types": "^13.6.2", - "before-after-hook": "^3.0.2", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/endpoint": { - "version": "10.1.3", - "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-10.1.3.tgz", - "integrity": "sha512-nBRBMpKPhQUxCsQQeW+rCJ/OPSMcj3g0nfHn01zGYZXuNDvvXudF/TYY6APj5THlurerpFN4a/dQAIAaM6BYhA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.6.2", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/graphql": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-8.2.1.tgz", - "integrity": "sha512-n57hXtOoHrhwTWdvhVkdJHdhTv0JstjDbDRhJfwIRNfFqmSo1DaK/mD2syoNUoLCyqSjBpGAKOG0BuwF392slw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/request": "^9.2.2", - "@octokit/types": "^13.8.0", - "universal-user-agent": "^7.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/openapi-types": { - "version": "24.2.0", - "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz", - "integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@octokit/plugin-paginate-rest": { - "version": "11.6.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-11.6.0.tgz", - "integrity": "sha512-n5KPteiF7pWKgBIBJSk8qzoZWcUkza2O6A0za97pMGVrGfPdltxrfmfF5GucHYvHGZD8BdaZmmHGz5cX/3gdpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.10.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/plugin-retry": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-retry/-/plugin-retry-7.2.0.tgz", - "integrity": "sha512-psMbEYb/Fh+V+ZaFo8J16QiFz4sVTv3GntCSU+hYqzHiMdc3P+hhHLVv+dJt0PGIPAGoIA5u+J2DCJdK6lEPsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/request-error": "^6.1.7", - "@octokit/types": "^13.6.2", - "bottleneck": "^2.15.3" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": ">=6" - } - }, - "node_modules/@octokit/plugin-throttling": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/@octokit/plugin-throttling/-/plugin-throttling-9.6.0.tgz", - "integrity": "sha512-zn7m1N3vpJDaVzLqjCRdJ0cRzNiekHEWPi8Ww9xyPNrDt5PStHvVE0eR8wy4RSU8Eg7YO8MHyvn6sv25EGVhhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.7.0", - "bottleneck": "^2.15.3" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@octokit/core": "^6.1.3" - } - }, - "node_modules/@octokit/request": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/@octokit/request/-/request-9.2.2.tgz", - "integrity": "sha512-dZl0ZHx6gOQGcffgm1/Sf6JfEpmh34v3Af2Uci02vzUYz6qEN6zepoRtmybWXIGXFIK8K9ylE3b+duCWqhArtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/endpoint": "^10.1.3", - "@octokit/request-error": "^6.1.7", - "@octokit/types": "^13.6.2", - "fast-content-type-parse": "^2.0.0", - "universal-user-agent": "^7.0.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/request-error": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-6.1.7.tgz", - "integrity": "sha512-69NIppAwaauwZv6aOzb+VVLwt+0havz9GT5YplkeJv7fG7a40qpLt/yZKyiDxAhgz0EtgNdNcb96Z0u+Zyuy2g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/types": "^13.6.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/@octokit/types": { - "version": "13.10.0", - "resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz", - "integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/openapi-types": "^24.2.0" - } - }, - "node_modules/@phenomnomnominal/tsquery": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@phenomnomnominal/tsquery/-/tsquery-5.0.1.tgz", - "integrity": "sha512-3nVv+e2FQwsW8Aw6qTU6f+1rfcJ3hrcnvH/mu9i8YhxO+9sqbOfpL8m6PbET5+xKOlz/VSbp0RoYWYCtIsnmuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "esquery": "^1.4.0" - }, - "peerDependencies": { - "typescript": "^3 || ^4 || ^5" - } - }, - "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/@pkgr/core": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.2.tgz", - "integrity": "sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "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/@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.1", - "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.1.tgz", - "integrity": "sha512-Z9cr0LgU/zgucbT9cksH0/pX9zmVda9hkDPcgIE0uvjMQ8w/mElDivGjx1w1pEQ+MuQJ5CBq3VCF16S6G4VH3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@octokit/core": "^6.0.0", - "@octokit/plugin-paginate-rest": "^11.0.0", - "@octokit/plugin-retry": "^7.0.0", - "@octokit/plugin-throttling": "^9.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.1", - "resolved": "https://registry.npmjs.org/@semantic-release/npm/-/npm-12.0.1.tgz", - "integrity": "sha512-/6nntGSUGK2aTOI0rHPwY3ZjgY9FkXmEHbW9Kr+62NVOsyqpKKeP0lrCH+tphv+EsNdJNmqqwijTEnVWUMQ2Nw==", - "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.5.0", - "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/@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/@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/execa": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", - "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.3", - "figures": "^6.1.0", - "get-stream": "^9.0.0", - "human-signals": "^8.0.0", - "is-plain-obj": "^4.1.0", - "is-stream": "^4.0.1", - "npm-run-path": "^6.0.0", - "pretty-ms": "^9.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.5.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/@semantic-release/npm/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/@semantic-release/npm/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/@semantic-release/npm/node_modules/human-signals": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", - "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "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/npm/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/@semantic-release/npm/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/@semantic-release/npm/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/@semantic-release/npm/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/@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/@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": "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/@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/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "13.0.5", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-13.0.5.tgz", - "integrity": "sha512-36/hTbH2uaWuGVERyC6da9YwGWnzUZXuPro/F2LfsdOsLnCojz/iSH8MxUt/FD2S5XBSVPhmArFUXcpCQ2Hkiw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", - "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "lodash.get": "^4.4.2", - "type-detect": "^4.1.0" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", - "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", - "dev": true, - "license": "(Unlicense OR Apache-2.0)" - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "license": "MIT", - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "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/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "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/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==", - "dev": true, - "license": "MIT" - }, - "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/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "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/node": { - "version": "22.13.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.13.tgz", - "integrity": "sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.20.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/responselike": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", - "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.18.0.tgz", - "integrity": "sha512-94EQTWZ40mzBc42ATNIBimBEDltSJ9RQHCC8vc/PDbxi4k8dVwUAv4o98dk50M1zB+JGFxp43FP7f8+FP8R6Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/type-utils": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/experimental-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", - "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/utils": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/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/@typescript-eslint/experimental-utils/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/@typescript-eslint/parser": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.18.0.tgz", - "integrity": "sha512-4Z+L8I2OqhZV8qA132M4wNL30ypZGYOQVBfMgxDH/K5UX0PNqTu1c6za9ST5r9+tavvHiTWmBnKzpCJ/GlVFtg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz", - "integrity": "sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz", - "integrity": "sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "7.18.0", - "@typescript-eslint/utils": "7.18.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.18.0.tgz", - "integrity": "sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz", - "integrity": "sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/visitor-keys": "7.18.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.18.0.tgz", - "integrity": "sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.18.0", - "@typescript-eslint/types": "7.18.0", - "@typescript-eslint/typescript-estree": "7.18.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.18.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz", - "integrity": "sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "7.18.0", - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.13.tgz", - "integrity": "sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/shared": "3.5.13", - "entities": "^4.5.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.13.tgz", - "integrity": "sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.13", - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/compiler-sfc": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.13.tgz", - "integrity": "sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.25.3", - "@vue/compiler-core": "3.5.13", - "@vue/compiler-dom": "3.5.13", - "@vue/compiler-ssr": "3.5.13", - "@vue/shared": "3.5.13", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.11", - "postcss": "^8.4.48", - "source-map-js": "^1.2.0" - } - }, - "node_modules/@vue/compiler-ssr": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.13.tgz", - "integrity": "sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/compiler-dom": "3.5.13", - "@vue/shared": "3.5.13" - } - }, - "node_modules/@vue/shared": { - "version": "3.5.13", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.13.tgz", - "integrity": "sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==", - "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-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/abortable-iterator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/abortable-iterator/-/abortable-iterator-5.1.0.tgz", - "integrity": "sha512-a3nRG0GOGw3IPFA2hdhrZU+QuD3mA6i+5f4YM/Obe+D5lYccxScI32rAIHAW5ttFV7+beiof09gHav4qUEZDwg==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "get-iterator": "^2.0.0", - "it-stream-types": "^2.0.1" - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "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.4.0", - "resolved": "https://registry.npmjs.org/acorn-loose/-/acorn-loose-8.4.0.tgz", - "integrity": "sha512-M0EUka6rb+QC4l9Z3T0nJEzNOO7JcoJlYMrBlyBCiFSXRyxjLKayd4TbQs2FDRWQU1h9FR7QVNHt+PEaoNL5rQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.11.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": "45.1.4", - "resolved": "https://registry.npmjs.org/aegir/-/aegir-45.1.4.tgz", - "integrity": "sha512-xS+AW251ok7GySAii4flQpQL3qdoGJdr2VJ3j5De84iAuDMPVi/eVxlVP3AmtQ22xcujUhUD3UgbZqgq7QlkCQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@electron/get": "^3.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/eslint-plugin": "^7.13.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": "^8.17.5", - "depcheck": "^1.4.3", - "diff": "^7.0.0", - "electron-mocha": "^13.0.0", - "env-paths": "^3.0.0", - "esbuild": "^0.25.0", - "eslint": "^8.31.0", - "eslint-config-ipfs": "^7.0.0", - "eslint-plugin-etc": "^2.0.2", - "eslint-plugin-import": "^2.18.0", - "eslint-plugin-jsdoc": "^48.9.1", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.1.1", - "execa": "^8.0.1", - "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", - "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.25.0", - "typedoc-plugin-mdn-links": "^3.0.3", - "typedoc-plugin-missing-exports": "^2.0.0", - "typescript": "^5.1.6", - "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.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "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/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-sequence-parser": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.3.tgz", - "integrity": "sha512-+fksAx9eG3Ab6LDnLs3ZqZa8KVJ/jYnX+D4Qe1azX+LFGFAXqynCQLOdLpNYN/l9e7l6hMWwZbrnctqr6eSQSw==", - "dev": true, - "license": "MIT" - }, - "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/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==", - "dev": true, - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "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==", - "dev": true, - "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.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "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", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "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.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/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/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/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-plugin-polyfill-corejs2": { - "version": "0.4.13", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.13.tgz", - "integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.22.6", - "@babel/helper-define-polyfill-provider": "^0.6.4", - "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.11.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.11.1.tgz", - "integrity": "sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.3", - "core-js-compat": "^3.40.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.4.tgz", - "integrity": "sha512-7gD3pRadPrbjhjLyxebmx/WrFYcuSjZ0XbdUujQMZ/fcE9oeewk2U/7PCvez84UeuK3oSjmPZ0Ch0dlupQvGzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.4" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "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/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "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": "3.0.2", - "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-3.0.2.tgz", - "integrity": "sha512-Nik3Sc0ncrMK4UUdXQmAnRtzmNQTAAXmXIopizwZ1W1t8QmfJj+zL4OA2I7XPTPW5z5TDqv4hRo/JzouDJnX3A==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "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==", - "dev": true, - "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.24.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz", - "integrity": "sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==", - "dev": true, - "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.30001688", - "electron-to-chromium": "^1.5.73", - "node-releases": "^2.0.19", - "update-browserslist-db": "^1.1.1" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/builtin-modules": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", - "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/builtins": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", - "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "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": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", - "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/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/cacheable-request/node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "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/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==", - "dev": true, - "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.30001707", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001707.tgz", - "integrity": "sha512-3qtRjw/HQSMlDWf+X79N206fepf4SOOU6SQLMaq/0KkZLmSjPxAkBOQQ+FxbHKfHmYLZFfdWsO3KA90ceHPSnw==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", - "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", - "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": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/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/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true, - "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/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/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/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/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-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==", - "dev": true, - "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/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/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==", - "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/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==", - "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/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/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": "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/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/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": "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/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==", - "dev": true, - "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/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.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-8.0.1.tgz", - "integrity": "sha512-hlqcy3xHred2gyYg/zXSMXraY2mjAYYo0msUCpK+BGyaVJMFCKWVXPIHiaacGO2GGp13kvHWXFhYmxT4QQqW3Q==", - "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.1.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-6.1.0.tgz", - "integrity": "sha512-5nxDo7TwKB5InYBl4ZC//1g9GRwB/F3TXOGR9hgUjMGfvSP4Vu5NkpNro2+1+TIEy1vwxApl5ircECr2ri5JIw==", - "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.41.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.41.0.tgz", - "integrity": "sha512-RFsU9LySVue9RTwdDVX/T0e2Y6jRYWXERKElIjpuEOEnxaXffI0X7RUwVzfYLfzuLXSNJDYoRYUAmRUcyln20A==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.24.4" - }, - "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": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.17.5.tgz", - "integrity": "sha512-l3Cfp87d7Yrodem675irdxV6+7+OsdR+jNwYHe33Dgnd6ePEfooYrvmfGdXF9rlQrNLUQp/HqYgHJzSq19UEsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-json-reporter": "8.17.5", - "@cspell/cspell-pipe": "8.17.5", - "@cspell/cspell-types": "8.17.5", - "@cspell/dynamic-import": "8.17.5", - "@cspell/url": "8.17.5", - "chalk": "^5.4.1", - "chalk-template": "^1.1.0", - "commander": "^13.1.0", - "cspell-dictionary": "8.17.5", - "cspell-gitignore": "8.17.5", - "cspell-glob": "8.17.5", - "cspell-io": "8.17.5", - "cspell-lib": "8.17.5", - "fast-json-stable-stringify": "^2.1.0", - "file-entry-cache": "^9.1.0", - "get-stdin": "^9.0.0", - "semver": "^7.7.1", - "tinyglobby": "^0.2.12" - }, - "bin": { - "cspell": "bin.mjs", - "cspell-esm": "bin.mjs" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/streetsidesoftware/cspell?sponsor=1" - } - }, - "node_modules/cspell-config-lib": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.17.5.tgz", - "integrity": "sha512-XDc+UJO5RZ9S9e2Ajz332XjT7dv6Og2UqCiSnAlvHt7t/MacLHSPARZFIivheObNkWZ7E1iWI681RxKoH4o40w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-types": "8.17.5", - "comment-json": "^4.2.5", - "yaml": "^2.7.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-dictionary": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.17.5.tgz", - "integrity": "sha512-O/Uuhv1RuDu+5WYQml0surudweaTvr+2YJSmPSdlihByUSiogCbpGqwrRow7wQv/C5p1W1FlFjotvUfoR0fxHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-pipe": "8.17.5", - "@cspell/cspell-types": "8.17.5", - "cspell-trie-lib": "8.17.5", - "fast-equals": "^5.2.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-gitignore": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.17.5.tgz", - "integrity": "sha512-I27fgOUZzH14jeIYo65LooB60fZ42f6OJL1lOR9Mk6IrIlDyUtzherGR+xx5KshK2katYkX42Qu4zsVYM6VFPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "8.17.5", - "cspell-glob": "8.17.5", - "cspell-io": "8.17.5", - "find-up-simple": "^1.0.0" - }, - "bin": { - "cspell-gitignore": "bin.mjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-glob": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.17.5.tgz", - "integrity": "sha512-OXquou7UykInlGV5et5lNKYYrW0dwa28aEF995x1ocANND7o0bbHmFlbgyci/Lp4uFQai8sifmfFJbuIg2IC/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/url": "8.17.5", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-grammar": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.17.5.tgz", - "integrity": "sha512-st2n+FVw25MvMbsGb3TeJNRr6Oih4g14rjOd/UJN0qn+ceH360SAShUFqSd4kHHu2ADazI/TESFU6FRtMTPNOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-pipe": "8.17.5", - "@cspell/cspell-types": "8.17.5" - }, - "bin": { - "cspell-grammar": "bin.mjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-io": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.17.5.tgz", - "integrity": "sha512-oevM/8l0s6nc1NCYPqNFumrW50QSHoa6wqUT8cWs09gtZdE2AWG0U6bIE8ZEVz6e6FxS+6IenGKTdUUwP0+3fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-service-bus": "8.17.5", - "@cspell/url": "8.17.5" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-lib": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.17.5.tgz", - "integrity": "sha512-S3KuOrcST1d2BYmTXA+hnbRdho5n3w5GUvEaCx3QZQBwAPfLpAwJbe2yig1TxBpyEJ5LqP02i/mDg1pUCOP0hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-bundled-dicts": "8.17.5", - "@cspell/cspell-pipe": "8.17.5", - "@cspell/cspell-resolver": "8.17.5", - "@cspell/cspell-types": "8.17.5", - "@cspell/dynamic-import": "8.17.5", - "@cspell/filetypes": "8.17.5", - "@cspell/strong-weak-map": "8.17.5", - "@cspell/url": "8.17.5", - "clear-module": "^4.1.2", - "comment-json": "^4.2.5", - "cspell-config-lib": "8.17.5", - "cspell-dictionary": "8.17.5", - "cspell-glob": "8.17.5", - "cspell-grammar": "8.17.5", - "cspell-io": "8.17.5", - "cspell-trie-lib": "8.17.5", - "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": ">=18" - } - }, - "node_modules/cspell-trie-lib": { - "version": "8.17.5", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.17.5.tgz", - "integrity": "sha512-9hjI3nRQxtGEua6CgnLbK3sGHLx9dXR/BHwI/csRL4dN5GGRkE5X3CCoy1RJVL7iGFLIzi43+L10xeFRmWniKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@cspell/cspell-pipe": "8.17.5", - "@cspell/cspell-types": "8.17.5", - "gensequence": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "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.2", - "resolved": "https://registry.npmjs.org/datastore-core/-/datastore-core-10.0.2.tgz", - "integrity": "sha512-B3WXxI54VxJkpXxnYibiF17si3bLXE1XOjrJB7wM5co9fx2KOEkiePDGiCCEtnapFHTnmAnYCPdA7WZTIpdn/A==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@libp2p/logger": "^5.0.1", - "interface-datastore": "^8.0.0", - "interface-store": "^6.0.0", - "it-drain": "^3.0.7", - "it-filter": "^3.1.1", - "it-map": "^3.1.1", - "it-merge": "^3.0.5", - "it-pipe": "^3.0.1", - "it-pushable": "^3.2.3", - "it-sort": "^3.0.6", - "it-take": "^3.0.6" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "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.1.0", - "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.1.0.tgz", - "integrity": "sha512-Wy+JTSbFThEOXQIR2L6mxJvEs+veIzpmqD7ynWxMXGpnk3smkHQOp6forLdHsKpAMW9iJpaBBIxz285t1n1C3w==", - "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.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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/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/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/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/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/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": "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/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": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.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/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.124", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.124.tgz", - "integrity": "sha512-riELkpDUqBi00gqreV3RIGoowxGrfueEKBd6zPdOk/I8lvuFpBGNkYoHof3zUHbiTBsIU8oxdIIL/WNrAG1/7A==", - "dev": true, - "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==", - "dev": true, - "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/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "once": "^1.4.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.0", - "resolved": "https://registry.npmjs.org/env-ci/-/env-ci-11.1.0.tgz", - "integrity": "sha512-Z8dnwSDbV1XYM9SBF2J0GcNVvmfmfh3a49qddGIROhBoVro6MZVTji15z/sJbQ2ko2ei8n988EU1wzoLU/tF+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "execa": "^8.0.0", - "java-properties": "^1.0.2" - }, - "engines": { - "node": "^18.17 || >=20.6.1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.9", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", - "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", - "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.3", - "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.0.0", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.0", - "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-regex": "^1.2.1", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.0", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.3", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.3", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.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.18" - }, - "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-module-lexer": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", - "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", - "dev": true, - "license": "MIT" - }, - "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.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", - "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.1", - "@esbuild/android-arm": "0.25.1", - "@esbuild/android-arm64": "0.25.1", - "@esbuild/android-x64": "0.25.1", - "@esbuild/darwin-arm64": "0.25.1", - "@esbuild/darwin-x64": "0.25.1", - "@esbuild/freebsd-arm64": "0.25.1", - "@esbuild/freebsd-x64": "0.25.1", - "@esbuild/linux-arm": "0.25.1", - "@esbuild/linux-arm64": "0.25.1", - "@esbuild/linux-ia32": "0.25.1", - "@esbuild/linux-loong64": "0.25.1", - "@esbuild/linux-mips64el": "0.25.1", - "@esbuild/linux-ppc64": "0.25.1", - "@esbuild/linux-riscv64": "0.25.1", - "@esbuild/linux-s390x": "0.25.1", - "@esbuild/linux-x64": "0.25.1", - "@esbuild/netbsd-arm64": "0.25.1", - "@esbuild/netbsd-x64": "0.25.1", - "@esbuild/openbsd-arm64": "0.25.1", - "@esbuild/openbsd-x64": "0.25.1", - "@esbuild/sunos-x64": "0.25.1", - "@esbuild/win32-arm64": "0.25.1", - "@esbuild/win32-ia32": "0.25.1", - "@esbuild/win32-x64": "0.25.1" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "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", - "peer": true, - "dependencies": { - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12" - }, - "peerDependencies": { - "eslint": ">=6.0.0" - } - }, - "node_modules/eslint-config-ipfs": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/eslint-config-ipfs/-/eslint-config-ipfs-7.0.6.tgz", - "integrity": "sha512-iID549DDGU+loFaTF9Oo6oxFyPstFvzRG9jjNP15+qpPeKxPXT8MCh6KL6b4TUaXlBD3znw32uag2zRVG+O/rQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "^7.5.0", - "@typescript-eslint/parser": "^7.5.0", - "eslint-config-love": "^47.0.0", - "eslint-config-standard": "^17.1.0", - "eslint-plugin-etc": "^2.0.3", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsdoc": "^48.9.1", - "eslint-plugin-no-only-tests": "^3.1.0", - "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^6.1.1" - }, - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/eslint-config-love": { - "version": "47.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-love/-/eslint-config-love-47.0.0.tgz", - "integrity": "sha512-wIeJhb4/NF7nE5Ltppg1e9dp1Auxx0+ZPRysrXQ3uBKlW4Nj/UiTZu4r3sKWCxo6HGcRcI4MC1Q5421y3fny2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/parser": "^7.0.1" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^7.0.1", - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0", - "typescript": "*" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", - "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", - "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", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", - "eslint-plugin-promise": "^6.0.0" - } - }, - "node_modules/eslint-etc": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-etc/-/eslint-etc-5.2.1.tgz", - "integrity": "sha512-lFJBSiIURdqQKq9xJhvSJFyPA+VeTh5xvk24e8pxVL7bwLBtGF60C/KRkLTMrvCZ6DA3kbPuYhLWY0TZMlqTsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/experimental-utils": "^5.0.0", - "tsutils": "^3.17.1", - "tsutils-etc": "^1.4.1" - }, - "peerDependencies": { - "eslint": "^8.0.0", - "typescript": ">=4.0.0" - } - }, - "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-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", - "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": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", - "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.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", - "peer": true, - "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-etc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-etc/-/eslint-plugin-etc-2.0.3.tgz", - "integrity": "sha512-o5RS/0YwtjlGKWjhKojgmm82gV1b4NQUuwk9zqjy9/EjxNFKKYCaF+0M7DkYBn44mJ6JYFZw3Ft249dkKuR1ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@phenomnomnominal/tsquery": "^5.0.0", - "@typescript-eslint/experimental-utils": "^5.0.0", - "eslint-etc": "^5.1.0", - "requireindex": "~1.2.0", - "tslib": "^2.0.0", - "tsutils": "^3.0.0" - }, - "peerDependencies": { - "eslint": "^8.0.0", - "typescript": ">=4.0.0" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", - "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/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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/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/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": "48.11.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.11.0.tgz", - "integrity": "sha512-d12JHJDPNo7IFwTOAItCeJY1hcqoIxE0lHA8infQByLilQ9xkqrRa6laWCnsuCrf+8rUnvxXY1XuTbibRBNylA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@es-joy/jsdoccomment": "~0.46.0", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.3.5", - "escape-string-regexp": "^4.0.0", - "espree": "^10.1.0", - "esquery": "^1.6.0", - "parse-imports": "^2.1.1", - "semver": "^7.6.3", - "spdx-expression-parse": "^4.0.0", - "synckit": "^0.9.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/eslint-visitor-keys": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", - "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-plugin-jsdoc/node_modules/espree": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.14.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-plugin-n": { - "version": "16.6.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", - "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "builtins": "^5.0.1", - "eslint-plugin-es-x": "^7.5.0", - "get-tsconfig": "^4.7.0", - "globals": "^13.24.0", - "ignore": "^5.2.4", - "is-builtin-module": "^3.2.1", - "is-core-module": "^2.12.1", - "minimatch": "^3.1.2", - "resolve": "^1.22.2", - "semver": "^7.5.3" - }, - "engines": { - "node": ">=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-n/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-n/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-n/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", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-n/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "peer": true, - "engines": { - "node": ">=10" - }, - "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-node": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", - "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-plugin-es": "^3.0.0", - "eslint-utils": "^2.0.0", - "ignore": "^5.1.1", - "minimatch": "^3.0.4", - "resolve": "^1.10.1", - "semver": "^6.1.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "peerDependencies": { - "eslint": ">=5.16.0" - } - }, - "node_modules/eslint-plugin-node/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-node/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-node/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-promise": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", - "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=4" - } - }, - "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/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/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint/node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/eslint/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/eslint/node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/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/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/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/eslint/node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.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==", - "dev": true, - "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/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": "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/execa/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/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/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": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-content-type-parse/-/fast-content-type-parse-2.0.1.tgz", - "integrity": "sha512-nGqtvLrj5w0naR6tDPfB4cUmYCqouzyQiz6C5y/LtcDllJdrcc6WaWW6iXyIIOErTa/XRybj28aasdn4LkVk6Q==", - "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==", - "dev": true, - "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/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/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/figures/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/file-entry-cache": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz", - "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "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": "5.0.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", - "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.3.1", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=18" - } - }, - "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/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/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.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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-iterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/get-iterator/-/get-iterator-2.0.1.tgz", - "integrity": "sha512-7HuY/hebu4gryTDT7O/XY/fvY9wRByEGdK6QOa4of8npTcv0+NS6frFKABcf6S9EBAsveTuKTsZQQBFMMNILIg==", - "license": "MIT" - }, - "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==", - "dev": true, - "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-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.0", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.10.0.tgz", - "integrity": "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A==", - "dev": true, - "license": "MIT", - "peer": true, - "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/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": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "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/ignore": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.3.tgz", - "integrity": "sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==", - "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/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": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "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==", - "dev": true, - "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==", - "dev": true, - "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/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.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/http-cookie-agent": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/http-cookie-agent/-/http-cookie-agent-6.0.8.tgz", - "integrity": "sha512-qnYh3yLSr2jBsTYkw11elq+T361uKAJaZ2dR4cfYZChw1dt9uL5t3zSUwehoqqVb4oldk1BpkXKm2oat8zV+oA==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.3" - }, - "engines": { - "node": ">=18.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/3846masa" - }, - "peerDependencies": { - "tough-cookie": "^4.0.0 || ^5.0.0", - "undici": "^5.11.0 || ^6.0.0" - }, - "peerDependenciesMeta": { - "undici": { - "optional": true - } - } - }, - "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": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.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==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "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/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/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==", - "dev": true, - "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.0.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.0.0.tgz", - "integrity": "sha512-sCO7uaLVhRJ25vz1o8s9IFM3nVS4DkuQnyjMwiQPKvQuBYBDmb8H7zx8ki7nVh4HJQOdVWebyvLE0qt+clruxA==", - "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.", - "dev": true, - "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==", - "dev": true, - "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.1", - "resolved": "https://registry.npmjs.org/interface-datastore/-/interface-datastore-8.3.1.tgz", - "integrity": "sha512-3r0ETmHIi6HmvM5sc09QQiCD3gUfwtEM/AAChOyAd/UAKT69uk8LXfTSUBufbUIO/dU65Vj8nb9O6QjwW8vDSQ==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "interface-store": "^6.0.0", - "uint8arrays": "^5.1.0" - } - }, - "node_modules/interface-store": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/interface-store/-/interface-store-6.0.2.tgz", - "integrity": "sha512-KSFCXtBlNoG0hzwNa0RmhHtrdhzexp+S+UY2s0rWTBJyfdEIgn6i6Zl9otVqrcFYbYrneBT7hbmHQ8gE0C3umA==", - "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/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==", - "dev": true, - "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-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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-builtin-module": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", - "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "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==", - "dev": true, - "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-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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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": "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/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==", - "dev": true, - "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==", - "dev": true, - "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.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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.7", - "resolved": "https://registry.npmjs.org/it-all/-/it-all-3.0.7.tgz", - "integrity": "sha512-PkuYtu6XhJzuPTKXImd6y0qE6H91MUPV/b9xotXMAI6GjmD2v3NoHj2g5L0lS2qZ0EzyGWZU1kp0UxW8POvNBQ==", - "dev": true, - "license": "Apache-2.0 OR MIT" - }, - "node_modules/it-byte-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/it-byte-stream/-/it-byte-stream-1.1.1.tgz", - "integrity": "sha512-OIOb8PvK9ZV7MHvyxIDNyN3jmrxrJdx99G0RIYYb3Tzo1OWv+O1C6mfg7nnlDuuTQz2POYFXe87AShKAEl+POw==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-queueless-pushable": "^1.0.0", - "it-stream-types": "^2.0.2", - "uint8arraylist": "^2.4.8" - } - }, - "node_modules/it-drain": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/it-drain/-/it-drain-3.0.8.tgz", - "integrity": "sha512-eeOz+WwKc11ou1UuqZympcXPLCjpTn5ALcYFJiHeTEiYEZ2py/J1vq41XWYj88huCUiqp9iNHfObOKrbIk5Izw==", - "dev": true, - "license": "Apache-2.0 OR MIT" - }, - "node_modules/it-filter": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/it-filter/-/it-filter-3.1.2.tgz", - "integrity": "sha512-2AozaGjIvBBiB7t7MpVNug9kwofqmKSpvgW7zhuyvCs6xxDd6FrfvqyfYtlQTKLNP+Io1WeXko1UQhdlK4M0gg==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-peekable": "^3.0.0" - } - }, - "node_modules/it-foreach": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/it-foreach/-/it-foreach-2.1.2.tgz", - "integrity": "sha512-PvXs3v1FaeWDhWzRxnwB4vSKJngxdLgi0PddkfurCvIFBmKTBfWONLeyDk5dxrvtCzdE4y96KzEQynk4/bbI5A==", - "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==", - "dev": true, - "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": "1.2.1", - "resolved": "https://registry.npmjs.org/it-length-prefixed-stream/-/it-length-prefixed-stream-1.2.1.tgz", - "integrity": "sha512-FYqlxc2toUoK+aPO5r3KDBIUG1mOvk2DzmjQcsfLUTHRWMJP4Va9855tVzg/22Bj+VUUaT7gxBg7HmbiCxTK4w==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-byte-stream": "^1.0.0", - "it-stream-types": "^2.0.2", - "uint8-varint": "^2.0.4", - "uint8arraylist": "^2.4.8" - } - }, - "node_modules/it-map": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/it-map/-/it-map-3.1.2.tgz", - "integrity": "sha512-G3dzFUjTYHKumJJ8wa9dSDS3yKm8L7qDUnAgzemOD0UMztwm54Qc2v97SuUCiAgbOz/aibkSLImfoFK09RlSFQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-peekable": "^3.0.0" - } - }, - "node_modules/it-merge": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/it-merge/-/it-merge-3.0.9.tgz", - "integrity": "sha512-TjY4WTiwe4ONmaKScNvHDAJj6Tw0UeQFp4JrtC/3Mq7DTyhytes7mnv5OpZV4gItpZcs0AgRntpT2vAy2cnXUw==", - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-queueless-pushable": "^2.0.0" - } - }, - "node_modules/it-merge/node_modules/it-queueless-pushable": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/it-queueless-pushable/-/it-queueless-pushable-2.0.0.tgz", - "integrity": "sha512-MlNnefWT/ntv5fesrHpxwVIu6ZdtlkN0A4aaJiE5wnmPMBv9ttiwX3UEMf78dFwIj5ZNaU9usYXg4swMEpUNJQ==", - "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-ndjson": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/it-ndjson/-/it-ndjson-1.1.2.tgz", - "integrity": "sha512-TPKpdYSNKjDdroCPnLamM5Up6XnPQ7F1KgNP3Ib5y5O4ayOVP+DHac/pzjUigcg9Kf9gkGVXDz8+FFKpWwoB3w==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "uint8arraylist": "^2.4.8" - } - }, - "node_modules/it-pair": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/it-pair/-/it-pair-2.0.6.tgz", - "integrity": "sha512-5M0t5RAcYEQYNG5BV7d7cqbdwbCAp5yLdzvkxsZmkuZsLbTdZzah6MQySYfaAQjNDCq6PUnDt0hqBZ4NwMfW6g==", - "dev": true, - "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.9", - "resolved": "https://registry.npmjs.org/it-parallel/-/it-parallel-3.0.9.tgz", - "integrity": "sha512-FSg8T+pr7Z1VUuBxEzAAp/K1j8r1e9mOcyzpWMxN3mt33WFhroFjWXV1oYSSjNqcdYwxD/XgydMVMktJvKiDog==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "p-defer": "^4.0.1" - } - }, - "node_modules/it-peekable": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/it-peekable/-/it-peekable-3.0.6.tgz", - "integrity": "sha512-odk9wn8AwFQipy8+tFaZNRCM62riraKZJRysfbmOett9wgJumCwgZFzWUBUwMoiQapEcEVGwjDpMChZIi+zLuQ==", - "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-protobuf-stream": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/it-protobuf-stream/-/it-protobuf-stream-1.1.6.tgz", - "integrity": "sha512-TxqgDHXTBt1XkYhrGKP8ubNsYD4zuTClSg6S1M0xTPsskGKA4nPFOGM60zrkh4NMB1Wt3EnsqM5U7kXkx60EXQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "it-length-prefixed-stream": "^1.0.0", - "it-stream-types": "^2.0.2", - "uint8arraylist": "^2.4.8" - } - }, - "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-queueless-pushable": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/it-queueless-pushable/-/it-queueless-pushable-1.0.2.tgz", - "integrity": "sha512-BFIm48C4O8+i+oVEPQpZ70+CaAsVUircvZtZCrpG2Q64933aLp+tDmas1mTBwqVBfIUUlg09d+e6SWW1CBuykQ==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "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==", - "dev": true, - "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.7", - "resolved": "https://registry.npmjs.org/it-sort/-/it-sort-3.0.7.tgz", - "integrity": "sha512-PsaKSd2Z0uhq8Mq5htdfsE/UagmdLCLWdBXPwi3FZGR4BTG180pFamhK+O+luFtBCNGRoqKAdtbZGTyGwA9uzw==", - "dev": true, - "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.7", - "resolved": "https://registry.npmjs.org/it-take/-/it-take-3.0.7.tgz", - "integrity": "sha512-0+EbsTvH1XCpwhhFkjWdqJTjzS5XP3KL69woBqwANNhMLKn0j39jk/WHIlvbg9XW2vEm7cZz4p8w5DkBZR8LoA==", - "dev": true, - "license": "Apache-2.0 OR MIT" - }, - "node_modules/it-to-buffer": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/it-to-buffer/-/it-to-buffer-4.0.8.tgz", - "integrity": "sha512-niZbR/+GbyQ2F2Nj79EJprT0gji5Si4nM1eJpgtlvfbvhsi5ZgA/y+mzSrOoNajiTC3svqvoNy8HGlTW2Faz/A==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "uint8arrays": "^5.1.0" - } - }, - "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/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", - "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", - "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==", - "dev": true, - "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==", - "dev": true, - "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==", - "dev": true, - "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/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/just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true, - "license": "MIT" - }, - "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.7.5", - "resolved": "https://registry.npmjs.org/ky/-/ky-1.7.5.tgz", - "integrity": "sha512-HzhziW6sc5m0pwi5M196+7cEBtbt0lCYi67wNsiwMUmz833wloE0gbzJPWKs1gliFKQb34huItDQX97LyOdPdA==", - "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/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": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/libp2p/-/libp2p-2.8.2.tgz", - "integrity": "sha512-LYZUWXcL5kQ+5VIiWhUWURLR7tgNBfwqGTLtZukMqjb33U/YAdd9lqW2MXjvaJLXPuGgRAatisDTOEP/ckfhWA==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "@chainsafe/is-ip": "^2.0.2", - "@chainsafe/netmask": "^2.0.0", - "@libp2p/crypto": "^5.0.15", - "@libp2p/interface": "^2.7.0", - "@libp2p/interface-internal": "^2.3.9", - "@libp2p/logger": "^5.1.13", - "@libp2p/multistream-select": "^6.0.20", - "@libp2p/peer-collections": "^6.0.25", - "@libp2p/peer-id": "^5.1.0", - "@libp2p/peer-store": "^11.1.2", - "@libp2p/utils": "^6.6.0", - "@multiformats/dns": "^1.0.6", - "@multiformats/multiaddr": "^12.3.5", - "@multiformats/multiaddr-matcher": "^1.6.0", - "any-signal": "^4.1.1", - "datastore-core": "^10.0.2", - "interface-datastore": "^8.3.1", - "it-byte-stream": "^1.1.0", - "it-merge": "^3.0.5", - "it-parallel": "^3.0.8", - "merge-options": "^3.0.4", - "multiformats": "^13.3.1", - "p-defer": "^4.0.1", - "p-retry": "^6.2.1", - "progress-events": "^1.0.1", - "race-event": "^1.3.0", - "race-signal": "^1.1.2", - "uint8arrays": "^5.1.0" - } - }, - "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/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-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/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/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/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/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/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/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/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/listr-verbose-renderer/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/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.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", - "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.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-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/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/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/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/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": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "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/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/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-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": "12.0.2", - "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", - "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", - "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/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/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==", - "dev": true, - "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-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==", - "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/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/mime/-/mime-4.0.6.tgz", - "integrity": "sha512-4rGt7rvQHBbaSOF9POGkk1ocRP16Md1x36Xma8sz8h8/vfCUI2OtEIeCqe4Ofes853x4xDoPiFLIT47J5fI/7A==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa" - ], - "license": "MIT", - "bin": { - "mime": "bin/cli.js" - }, - "engines": { - "node": ">=16" - } - }, - "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/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": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "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/mocha": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-11.1.0.tgz", - "integrity": "sha512-8uJR5RTC2NgpY3GrYcgpZrsEd9zKbPDpob1RezyR2upGHRQtHWofmzTMzTMSV6dru3tj5Ukt0+Vnq1qhFEEwAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.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": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "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/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/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "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/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "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.0.6", - "resolved": "https://registry.npmjs.org/mortice/-/mortice-3.0.6.tgz", - "integrity": "sha512-xUjsTQreX8rO3pHuGYDZ3PY/sEiONIzqzjLeog5akdY4bz9TlDDuvYlU8fm+6qnm4rnpa6AFxLhsfSBThLijdA==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "dependencies": { - "observable-webworkers": "^2.0.1", - "p-queue": "^8.0.1", - "p-timeout": "^6.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==", - "dev": true, - "license": "MIT" - }, - "node_modules/multiformats": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/multiformats/-/multiformats-13.3.2.tgz", - "integrity": "sha512-qbB0CQDt3QKfiAzZ5ZYjLFOs+zW43vA4uyM8g27PeEuXZybUOFyjrVdP93HPBHMoglibwfkdVwbzfUq8qGcH6g==", - "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.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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/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/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/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/nise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/nise/-/nise-6.1.1.tgz", - "integrity": "sha512-aMSAzLVY7LyeM60gvBS423nBmIPP+Wy7St7hsb+8/fc1HmeoHJfLO8CKse4u3BtOZvQLJghYPI2i/1WZrEj5/g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^13.0.1", - "@sinonjs/text-encoding": "^0.7.3", - "just-extend": "^6.2.0", - "path-to-regexp": "^8.1.0" - } - }, - "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-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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.1.tgz", - "integrity": "sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.9.2.tgz", - "integrity": "sha512-iriPEPIkoMYUy3F6f3wwSZAU93E0Eg6cHwIR6jzzOXWSy+SD/rOODEs74cVONHKSx2obXtuUoyidVEhISrisgQ==", - "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.0", - "@npmcli/config": "^9.0.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^4.0.2", - "@npmcli/package-json": "^6.1.0", - "@npmcli/promise-spawn": "^8.0.2", - "@npmcli/redact": "^3.0.0", - "@npmcli/run-script": "^9.0.1", - "@sigstore/tuf": "^3.0.0", - "abbrev": "^3.0.0", - "archy": "~1.0.0", - "cacache": "^19.0.1", - "chalk": "^5.3.0", - "ci-info": "^4.1.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.0.2", - "ini": "^5.0.0", - "init-package-json": "^7.0.2", - "is-cidr": "^5.1.0", - "json-parse-even-better-errors": "^4.0.0", - "libnpmaccess": "^9.0.0", - "libnpmdiff": "^7.0.0", - "libnpmexec": "^9.0.0", - "libnpmfund": "^6.0.0", - "libnpmhook": "^11.0.0", - "libnpmorg": "^7.0.0", - "libnpmpack": "^8.0.0", - "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.0.0", - "nopt": "^8.0.0", - "normalize-package-data": "^7.0.0", - "npm-audit-report": "^6.0.0", - "npm-install-checks": "^7.1.1", - "npm-package-arg": "^12.0.0", - "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": "^4.0.0", - "pacote": "^19.0.1", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "qrcode-terminal": "^0.12.0", - "read": "^4.0.0", - "semver": "^7.6.3", - "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.0", - "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/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/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-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/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.0", - "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.1", - "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-inflight": "^1.0.1", - "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.1.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", - "normalize-package-data": "^7.0.0", - "proc-log": "^5.0.0", - "semver": "^7.5.3" - }, - "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.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^6.1.2" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/redact": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "9.0.2", - "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.3.2", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2", - "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.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/agent-base": { - "version": "7.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/aggregate-error": { - "version": "3.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "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.1", - "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/minizlib": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "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/p-map": { - "version": "7.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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.3.0", - "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.1.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.1", - "dev": true, - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "^5.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/clean-stack": { - "version": "2.2.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "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.3.7", - "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.1", - "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.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "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.0.2", - "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.1.1", - "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.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.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/indent-string": { - "version": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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.0", - "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.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.0", - "@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.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.0", - "@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.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.0" - }, - "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.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.0", - "@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.0", - "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-fetch/node_modules/minizlib": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "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": "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/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/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.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "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", - "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/minizlib": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "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.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "^2.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/nopt/node_modules/abbrev": { - "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.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.0", - "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-registry-fetch/node_modules/minizlib": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.4", - "rimraf": "^5.0.5" - }, - "engines": { - "node": ">= 18" - } - }, - "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": "4.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "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": "6.1.2", - "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-inflight": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC" - }, - "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.0.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/rimraf": { - "version": "5.0.10", - "dev": true, - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^10.3.7" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "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.6.3", - "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.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.0.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "@sigstore/sign": "^3.0.0", - "@sigstore/tuf": "^3.0.0", - "@sigstore/verify": "^2.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/bundle": { - "version": "3.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.3.2" - }, - "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.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.0.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.3.2", - "make-fetch-happen": "^14.0.1", - "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.0.0", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.0.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.3.2" - }, - "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.3", - "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.4", - "dev": true, - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.1", - "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.20", - "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/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/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.0", - "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/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/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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/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/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/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.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/observable-webworkers": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/observable-webworkers/-/observable-webworkers-2.0.1.tgz", - "integrity": "sha512-JI1vB0u3pZjoQKOK1ROWzp0ygxSi7Yb0iR+7UNsw4/Zn4cQ0P3R7XL38zac/Dy2tEA7Lg88/wIJTjF8vYXZ0uw==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - } - }, - "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==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "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/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", - "dev": true, - "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": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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==", - "dev": true, - "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": "6.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz", - "integrity": "sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.1.1" - }, - "engines": { - "node": ">=18" - }, - "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-locate/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/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/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==", - "dev": true, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/p-wait-for": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/p-wait-for/-/p-wait-for-5.0.2.tgz", - "integrity": "sha512-lwx6u1CotQYPVju77R+D0vFomni/AqRfqLmqQ8hekklqZ6gAY9rONh7lBQ0uxWMkC2AuX9b2DVAl8To0NyP1JA==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-timeout": "^6.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/parse-imports/-/parse-imports-2.2.1.tgz", - "integrity": "sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==", - "dev": true, - "license": "Apache-2.0 AND MIT", - "dependencies": { - "es-module-lexer": "^1.5.3", - "slashes": "^3.0.12" - }, - "engines": { - "node": ">= 18" - } - }, - "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/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/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/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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/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==", - "dev": true, - "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==", - "dev": true, - "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-to-regexp": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", - "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "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/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==", - "dev": true, - "license": "ISC" - }, - "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/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/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.50.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.50.1.tgz", - "integrity": "sha512-ra9fsNWayuYumt+NiM069M6OkcRb1FZSK8bgi66AtpFoWkg2+y0bJSNmkFrWhMbEBbVKC/EruAHH3g0zmtwGmQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test": { - "version": "14.1.9", - "resolved": "https://registry.npmjs.org/playwright-test/-/playwright-test-14.1.9.tgz", - "integrity": "sha512-L6HkKrcaW+qhaIPPOsoR1HDDR3bQdKeQCcpLkCbebZDG1ikSzMwmF3HAcEtAUXbmRwZcvB1dPoxQi6jlCF/f+A==", - "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": "^3.6.0", - "cpy": "^11.0.0", - "esbuild": "0.23.0", - "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.50.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/@esbuild/aix-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", - "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/android-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", - "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/android-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", - "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/android-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", - "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/darwin-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", - "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/darwin-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", - "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", - "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/freebsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", - "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", - "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", - "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", - "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-loong64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", - "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-mips64el": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", - "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", - "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-riscv64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", - "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-s390x": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", - "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/linux-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", - "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/netbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", - "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", - "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/openbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", - "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/sunos-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", - "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/win32-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", - "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/win32-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", - "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/node_modules/@esbuild/win32-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", - "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright-test/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/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/esbuild": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", - "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.0", - "@esbuild/android-arm": "0.23.0", - "@esbuild/android-arm64": "0.23.0", - "@esbuild/android-x64": "0.23.0", - "@esbuild/darwin-arm64": "0.23.0", - "@esbuild/darwin-x64": "0.23.0", - "@esbuild/freebsd-arm64": "0.23.0", - "@esbuild/freebsd-x64": "0.23.0", - "@esbuild/linux-arm": "0.23.0", - "@esbuild/linux-arm64": "0.23.0", - "@esbuild/linux-ia32": "0.23.0", - "@esbuild/linux-loong64": "0.23.0", - "@esbuild/linux-mips64el": "0.23.0", - "@esbuild/linux-ppc64": "0.23.0", - "@esbuild/linux-riscv64": "0.23.0", - "@esbuild/linux-s390x": "0.23.0", - "@esbuild/linux-x64": "0.23.0", - "@esbuild/netbsd-x64": "0.23.0", - "@esbuild/openbsd-arm64": "0.23.0", - "@esbuild/openbsd-x64": "0.23.0", - "@esbuild/sunos-x64": "0.23.0", - "@esbuild/win32-arm64": "0.23.0", - "@esbuild/win32-ia32": "0.23.0", - "@esbuild/win32-x64": "0.23.0" - } - }, - "node_modules/playwright-test/node_modules/execa": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", - "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.3", - "figures": "^6.1.0", - "get-stream": "^9.0.0", - "human-signals": "^8.0.0", - "is-plain-obj": "^4.1.0", - "is-stream": "^4.0.1", - "npm-run-path": "^6.0.0", - "pretty-ms": "^9.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.5.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/playwright-test/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/playwright-test/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/playwright-test/node_modules/human-signals": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", - "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/playwright-test/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/playwright-test/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/playwright-test/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/playwright-test/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/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.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", - "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.8", - "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-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/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/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.5.0", - "resolved": "https://registry.npmjs.org/protons-runtime/-/protons-runtime-5.5.0.tgz", - "integrity": "sha512-EsALjF9QsrEk6gbCx3lmfHxVN0ah7nG3cY7GySD4xf4g8cr7g543zB88Foh897Sr1RQJ9yDCUsoT1i1H/cVUFA==", - "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.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", - "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", - "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/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.3.0", - "resolved": "https://registry.npmjs.org/race-event/-/race-event-1.3.0.tgz", - "integrity": "sha512-kaLm7axfOnahIqD3jQ4l1e471FIFcEGebXEnhxyLscuUzV8C94xVHtWEqDDXxll7+yu/6lW0w1Ff4HbtvHvOHg==", - "license": "Apache-2.0 OR MIT" - }, - "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/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-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/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/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-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-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.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.2.0.tgz", - "integrity": "sha512-eONBZy4hm2AgxjNFd8a4nyDJnzUAH0g34xSQAwWEVGCjdZ4ZL7dKZBfq267GWP/JaS9zW62Xs2FeAdDvpHHJGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "index-to-position": "^1.0.0", - "type-fest": "^4.37.0" - }, - "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/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.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "dev": true, - "license": "MIT" - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "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/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "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==", - "dev": true, - "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/requireindex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.2.0.tgz", - "integrity": "sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.5" - } - }, - "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==", - "dev": true, - "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", - "peer": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "license": "MIT", - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "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/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/restore-cursor/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/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==", - "dev": true, - "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.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", - "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "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.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", - "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", - "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.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "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/rxjs/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/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/semantic-release": { - "version": "24.2.3", - "resolved": "https://registry.npmjs.org/semantic-release/-/semantic-release-24.2.3.tgz", - "integrity": "sha512-KRhQG9cUazPavJiJEFIJ3XAMjgfd0fcK3B+T26qOl8L0UG5aZUjeRfREO0KM5InGtYwxqiiytkJrbcYoLDEv0A==", - "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.0", - "@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": "^12.0.0", - "marked-terminal": "^7.0.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/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/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-monorepo/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/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/@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/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/execa": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/execa/-/execa-9.5.2.tgz", - "integrity": "sha512-EHlpxMCpHWSAh1dgS6bVeoLAXGnJNdR93aabr4QCGbzOM73o5XmRfM/e5FUqsw3aagP8S8XEWUWFAxnRBnAF0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sindresorhus/merge-streams": "^4.0.0", - "cross-spawn": "^7.0.3", - "figures": "^6.1.0", - "get-stream": "^9.0.0", - "human-signals": "^8.0.0", - "is-plain-obj": "^4.1.0", - "is-stream": "^4.0.1", - "npm-run-path": "^6.0.0", - "pretty-ms": "^9.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^4.0.0", - "yoctocolors": "^2.0.0" - }, - "engines": { - "node": "^18.19.0 || >=20.5.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/semantic-release/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/semantic-release/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/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.0.2", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-8.0.2.tgz", - "integrity": "sha512-sYKnA7eGln5ov8T8gnYlkSOxFJvywzEx9BueN6xo/GKO8PGiI6uK6xx+DIGe45T3bdVjLAQDQW1aicT8z8JwQg==", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/semantic-release/node_modules/human-signals": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.0.tgz", - "integrity": "sha512-/1/GPCpDUCCYwlERiYjxoczfP0zfvZMU/OWgQPMya9AbAE24vseigFdhAMObpc8Q4lc/kjutPfUddDYyAmejnA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.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/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/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/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/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/semantic-release/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/semantic-release/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/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "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/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/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/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/shiki": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", - "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" - } - }, - "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/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/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/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/signale/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/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/sinon": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-20.0.0.tgz", - "integrity": "sha512-+FXOAbdnj94AQIxH0w1v8gzNxkawVvNqE3jUzRLptR71Oykeu2RrQXXl/VQjKay+Qnh73fDt/oDfMo6xMeDQbQ==", - "dev": true, - "license": "BSD-3-Clause", - "peer": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "@sinonjs/fake-timers": "^13.0.5", - "@sinonjs/samsam": "^8.0.1", - "diff": "^7.0.0", - "supports-color": "^7.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/sinon-ts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sinon-ts/-/sinon-ts-2.0.0.tgz", - "integrity": "sha512-fhwqbvf8Vc2vPr0TWUHbdKI/Y/q0nNSN6MLMCYYELFsQ2Y3M7qekn8CXxjC1URcjFk+H9c63lif7hKFBRSpWOg==", - "dev": true, - "license": "Apache-2.0 OR MIT", - "peerDependencies": { - "sinon": "*" - } - }, - "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.28", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", - "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", - "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/slashes": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/slashes/-/slashes-3.0.12.tgz", - "integrity": "sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==", - "dev": true, - "license": "ISC" - }, - "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/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "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==", - "dev": true, - "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.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "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==", - "dev": true, - "license": "BSD-3-Clause" - }, - "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/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/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/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/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/string-width/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/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": "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": { - "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": "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-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": "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/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.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", - "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", - "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==", - "dev": true, - "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/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, - "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/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/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/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "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/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.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.4.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tldts": { - "version": "6.1.85", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.85.tgz", - "integrity": "sha512-gBdZ1RjCSevRPFix/hpaUWeak2/RNUZB4/8frF1r5uYMHjFptkiT0JXIebWvgI/0ZHXvxaUDDJshiA0j6GdL3w==", - "license": "MIT", - "dependencies": { - "tldts-core": "^6.1.85" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "6.1.85", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.85.tgz", - "integrity": "sha512-DTjUVvxckL1fIoPSb3KE7ISNtkWSawZdpfxGxwiIrZoO6EbHVDXXUIlIuWympPaeS+BLGyggozX/HTMsRAdsoA==", - "license": "MIT" - }, - "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/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==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "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/tough-cookie": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", - "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^6.1.32" - }, - "engines": { - "node": ">=16" - } - }, - "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": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.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": "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" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils-etc": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/tsutils-etc/-/tsutils-etc-1.4.2.tgz", - "integrity": "sha512-2Dn5SxTDOu6YWDNKcx1xu2YUy6PUeKrWZB/x2cQ8vY2+iz3JRembKn/iZ0JLT1ZudGNwQQvtFX9AwvRHbXuPUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs": "^17.0.0", - "yargs": "^17.0.0" - }, - "bin": { - "ts-flags": "bin/ts-flags", - "ts-kind": "bin/ts-kind" - }, - "peerDependencies": { - "tsutils": "^3.0.0", - "typescript": ">=4.0.0" - } - }, - "node_modules/tsutils/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.38.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.38.0.tgz", - "integrity": "sha512-2dBz5D5ycHIoliLYLi0Q2V7KRaDlH0uWIvmk7TYlAg5slqwiPv1ezJdZm1QEM0xgk29oYWMCbIG7E6gHpvChlg==", - "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.25.13", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.13.tgz", - "integrity": "sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "lunr": "^2.3.9", - "marked": "^4.3.0", - "minimatch": "^9.0.3", - "shiki": "^0.14.7" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 16" - }, - "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x" - } - }, - "node_modules/typedoc-plugin-mdn-links": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/typedoc-plugin-mdn-links/-/typedoc-plugin-mdn-links-3.3.8.tgz", - "integrity": "sha512-Aewg+SW7hBdffRpT6WnpRwWthoaF9irlzXDKRyvcDVekPZSFujOlh690SV6eCgqrtP7GBJmN0TVeJUq6+6rb1w==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "typedoc": ">= 0.23.14 || 0.24.x || 0.25.x || 0.26.x" - } - }, - "node_modules/typedoc-plugin-missing-exports": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.3.0.tgz", - "integrity": "sha512-iI9ITNNLlbsLCBBeYDyu0Qqp3GN/9AGyWNKg8bctRXuZEPT7G1L+0+MNWG9MsHcf/BFmNbXL0nQ8mC/tXRicog==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "typedoc": "0.24.x || 0.25.x" - } - }, - "node_modules/typedoc/node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, - "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/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/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/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": { - "version": "6.21.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.2.tgz", - "integrity": "sha512-uROZWze0R0itiAKVPsYhFov9LxrPMHLMEQFszeI2gCN6bnIIZ8twzBCJcN2LJrBBLfrP0t1FW0g+JmKVl8Vk1g==", - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, - "node_modules/undici-types": { - "version": "6.20.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", - "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", - "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.2", - "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-7.0.2.tgz", - "integrity": "sha512-0JCqzSKnStlRRQfCdowvqy3cy0Dvtlb8xecj/H8JFZuCze4rwjPZQOgvFvn0Ws/usCHQFGpyr+pB9adaGwXn4Q==", - "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/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==", - "dev": true, - "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/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/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-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true, - "license": "MIT" - }, - "node_modules/vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "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/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/wherearewe": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wherearewe/-/wherearewe-2.0.1.tgz", - "integrity": "sha512-XUguZbDxCA2wBn2LoFtcEhXL6AXo+hVjGonwhSTTTU9SzbWG8Xu3onNIpzf9j/mYUcJQ0f+m37SzG77G851uFw==", - "dev": true, - "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": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "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/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/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==", - "dev": true, - "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/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==", - "dev": true, - "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==", - "dev": true, - "license": "ISC" - }, - "node_modules/yaml": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", - "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, - "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==", - "dev": true, - "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/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/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==", - "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/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": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "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" - } - } - } -} diff --git a/package.json b/package.json index 8d75055..7501ab4 100644 --- a/package.json +++ b/package.json @@ -1,197 +1,55 @@ { - "name": "@libp2p/http-fetch", - "version": "2.2.2", - "description": "Implementation of the WHATWG Fetch API on libp2p streams", - "author": "@marcopolo", + "name": "js-libp2p-http-monorepo", + "version": "1.0.0", + "description": "Accept HTTP requests over libp2p streams and/or use libp2p protocols over HTTP", "license": "Apache-2.0 OR MIT", - "homepage": "https://github.com/libp2p/js-libp2p-http-fetch#readme", + "homepage": "https://github.com/libp2p/js-libp2p-http#readme", "repository": { "type": "git", - "url": "git+https://github.com/libp2p/js-libp2p-http-fetch.git" + "url": "git+https://github.com/libp2p/js-libp2p-http.git" }, "bugs": { - "url": "https://github.com/libp2p/js-libp2p-http-fetch/issues" - }, - "publishConfig": { - "access": "public", - "provenance": true - }, - "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" - }, - "./auth": { - "types": "./dist/src/auth/index.d.ts", - "import": "./dist/src/auth/index.js" - }, - "./ping": { - "types": "./dist/src/ping.d.ts", - "import": "./dist/src/ping.js" - }, - "./well-known-handler": { - "types": "./dist/src/well-known-handler.d.ts", - "import": "./dist/src/well-known-handler.js" - } - }, - "eslintConfig": { - "extends": "ipfs", - "parserOptions": { - "project": true, - "sourceType": "module" - } - }, - "release": { - "branches": [ - "main" - ], - "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" - ] + "url": "https://github.com/libp2p/js-libp2p-http/issues" }, + "private": true, "scripts": { - "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:webkit": "aegir test -t browser -- --browser webkit", - "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", + "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", + "start": "aegir run start", + "release": "run-s build docs:no-publish npm:release docs", + "npm:release": "aegir run release --concurrency 1", "docs": "aegir docs", - "release": "aegir release" - }, - "dependencies": { - "@achingbrain/http-parser-js": "^0.5.8", - "@libp2p/crypto": "^5.0.6", - "@libp2p/interface": "^2.2.0", - "@libp2p/interface-internal": "^2.0.10", - "@libp2p/peer-id": "^5.0.7", - "@multiformats/multiaddr": "^12.3.0", - "@multiformats/multiaddr-to-uri": "^11.0.0", - "http-cookie-agent": "^6.0.7", - "p-defer": "^4.0.1", - "tough-cookie": "^5.0.0", - "uint8-varint": "^2.0.4", - "uint8arraylist": "^2.4.8", - "uint8arrays": "^5.1.0", - "undici": "^6.21.0" + "docs:no-publish": "aegir docs --publish false" }, "devDependencies": { - "@libp2p/interface-compliance-tests": "^6.1.8", - "@libp2p/logger": "^5.1.3", - "aegir": "^45.0.0", - "it-pair": "^2.0.6", - "libp2p": "^2.2.1", - "sinon-ts": "^2.0.0" + "aegir": "^47.0.16", + "npm-run-all": "^4.1.5" }, - "browser": { - "./dist/src/auth/agent.js": "./dist/src/auth/agent.browser.js" + "eslintConfig": { + "extends": "ipfs", + "ignorePatterns": [ + "!.aegir.js" + ] }, - "sideEffects": false + "workspaces": [ + "examples/*", + "packages/*" + ] } diff --git a/CHANGELOG.md b/packages/http-fetch/CHANGELOG.md similarity index 75% rename from CHANGELOG.md rename to packages/http-fetch/CHANGELOG.md index 36256a5..ecabc7c 100644 --- a/CHANGELOG.md +++ b/packages/http-fetch/CHANGELOG.md @@ -1,4 +1,4 @@ -## [2.2.2](https://github.com/libp2p/js-libp2p-http-fetch/compare/v2.2.1...v2.2.2) (2025-03-26) +## [@libp2p/http-fetch-2.2.2](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-2.2.1...@libp2p/http-fetch-2.2.2) (2025-03-26) ### Bug Fixes @@ -8,13 +8,13 @@ * **deps:** bump golang.org/x/crypto ([#50](https://github.com/libp2p/js-libp2p-http-fetch/issues/50)) ([c5407c6](https://github.com/libp2p/js-libp2p-http-fetch/commit/c5407c62d29a8376f720ba256f58ab7a718be823)) -## [2.2.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/v2.2.0...v2.2.1) (2025-03-26) +## [@libp2p/http-fetch-2.2.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-2.2.0...@libp2p/http-fetch-2.2.1) (2025-03-26) ### Bug Fixes * replace @perseveranza-pets/milo with @achingbrain/http-parser-js ([#51](https://github.com/libp2p/js-libp2p-http-fetch/issues/51)) ([7466502](https://github.com/libp2p/js-libp2p-http-fetch/commit/7466502a51f87a2626a53fb0ad4607e06e7d716c)), closes [#35](https://github.com/libp2p/js-libp2p-http-fetch/issues/35) -## [2.2.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/v2.1.1...v2.2.0) (2025-03-26) +## [@libp2p/http-fetch-2.2.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-2.1.1...@libp2p/http-fetch-2.2.0) (2025-03-26) ### Features @@ -24,7 +24,7 @@ * update comment style ([#52](https://github.com/libp2p/js-libp2p-http-fetch/issues/52)) ([37a6a74](https://github.com/libp2p/js-libp2p-http-fetch/commit/37a6a74c262763beed0035e038484a6c215793ed)) -## [2.1.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/v2.1.0...v2.1.1) (2024-12-11) +## [@libp2p/http-fetch-2.1.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-2.1.0...@libp2p/http-fetch-2.1.1) (2024-12-11) ### Bug Fixes @@ -34,25 +34,25 @@ * bump @multiformats/multiaddr-to-uri from 10.1.2 to 11.0.0 ([#46](https://github.com/libp2p/js-libp2p-http-fetch/issues/46)) ([a7960e6](https://github.com/libp2p/js-libp2p-http-fetch/commit/a7960e6f0fe6823ac4fe62712f8534fc13add9ae)) -## [2.1.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/v2.0.2...v2.1.0) (2024-11-01) +## [@libp2p/http-fetch-2.1.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-2.0.2...@libp2p/http-fetch-2.1.0) (2024-11-01) ### Features * Authenticated Fetch ([#45](https://github.com/libp2p/js-libp2p-http-fetch/issues/45)) ([ca69dc4](https://github.com/libp2p/js-libp2p-http-fetch/commit/ca69dc41fb53b8808e40ff5745cb85b0521fbc15)) -## [2.0.2](https://github.com/libp2p/js-libp2p-http-fetch/compare/v2.0.1...v2.0.2) (2024-10-29) +## [@libp2p/http-fetch-2.0.2](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-2.0.1...@libp2p/http-fetch-2.0.2) (2024-10-29) ### Bug Fixes * allow aborting authentication ([#43](https://github.com/libp2p/js-libp2p-http-fetch/issues/43)) ([3494773](https://github.com/libp2p/js-libp2p-http-fetch/commit/3494773844cf68f0f89d2dca1c857deb923e4c90)) -## [2.0.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/v2.0.0...v2.0.1) (2024-10-29) +## [@libp2p/http-fetch-2.0.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-2.0.0...@libp2p/http-fetch-2.0.1) (2024-10-29) ### Bug Fixes * update export paths ([#42](https://github.com/libp2p/js-libp2p-http-fetch/issues/42)) ([ca914d3](https://github.com/libp2p/js-libp2p-http-fetch/commit/ca914d324410634b388da03ba2f2b933eb11c08b)) -## [2.0.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/v1.1.1...v2.0.0) (2024-10-29) +## [@libp2p/http-fetch-2.0.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-1.1.1...@libp2p/http-fetch-2.0.0) (2024-10-29) ### âš  BREAKING CHANGES @@ -62,7 +62,7 @@ * bump @libp2p/interface from 1.7.0 to 2.2.0 ([#34](https://github.com/libp2p/js-libp2p-http-fetch/issues/34)) ([2945813](https://github.com/libp2p/js-libp2p-http-fetch/commit/2945813b0f401a43c49e6bb62ceba6db9783cb29)) -## [1.1.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/v1.1.0...v1.1.1) (2024-10-29) +## [@libp2p/http-fetch-1.1.1](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-1.1.0...@libp2p/http-fetch-1.1.1) (2024-10-29) ### Trivial Changes @@ -74,7 +74,7 @@ * **dev:** bump aegir from 43.0.3 to 45.0.0 ([#33](https://github.com/libp2p/js-libp2p-http-fetch/issues/33)) ([8216a10](https://github.com/libp2p/js-libp2p-http-fetch/commit/8216a103a7b1f46b97eee02d132e103093901a67)) -## [1.1.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/v1.0.0...v1.1.0) (2024-06-13) +## [@libp2p/http-fetch-1.1.0](https://github.com/libp2p/js-libp2p-http-fetch/compare/@libp2p/http-fetch-1.0.0...@libp2p/http-fetch-1.1.0) (2024-06-13) ### Features @@ -86,7 +86,7 @@ * Remove debug logging ([2806d9e](https://github.com/libp2p/js-libp2p-http-fetch/commit/2806d9eca5ed9f06489ba5af7d0d017d333c4ec5)) -## 1.0.0 (2024-06-12) +## @libp2p/http-fetch-1.0.0 (2024-06-12) ### Trivial Changes diff --git a/packages/http-fetch/CODE_OF_CONDUCT.md b/packages/http-fetch/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b0fa54 --- /dev/null +++ b/packages/http-fetch/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/packages/http-fetch/LICENSE-APACHE b/packages/http-fetch/LICENSE-APACHE new file mode 100644 index 0000000..b09cd78 --- /dev/null +++ b/packages/http-fetch/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/packages/http-fetch/LICENSE-MIT b/packages/http-fetch/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/http-fetch/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/packages/http-fetch/README.md b/packages/http-fetch/README.md new file mode 100644 index 0000000..37e0ac7 --- /dev/null +++ b/packages/http-fetch/README.md @@ -0,0 +1,58 @@ +# @libp2p/http-fetch + +[![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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> libp2p-compatible implementation of the fetch API + +# About + + + +This is an implementation of the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) +that uses libp2p streams as the underlying transport layer, instead of a TCP +socket. + +# Install + +```console +$ npm i @libp2p/http-fetch +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-fetch/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-fetch/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/packages/http-fetch/package.json b/packages/http-fetch/package.json new file mode 100644 index 0000000..6b9065b --- /dev/null +++ b/packages/http-fetch/package.json @@ -0,0 +1,155 @@ +{ + "name": "@libp2p/http-fetch", + "version": "2.2.2", + "description": "libp2p-compatible implementation of the fetch API", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-fetch#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/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" + } + }, + "release": { + "branches": [ + "main" + ], + "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": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check", + "release": "aegir release" + }, + "dependencies": { + "@achingbrain/http-parser-js": "^0.5.9", + "@libp2p/http-utils": "~0.0.0", + "@libp2p/interface": "^2.10.2", + "it-byte-stream": "^2.0.2", + "uint8arrays": "^5.1.0" + }, + "devDependencies": { + "@libp2p/logger": "^5.1.18", + "aegir": "^47.0.16", + "it-drain": "^3.0.9", + "it-pair": "^2.0.6", + "sinon-ts": "^2.0.0" + }, + "sideEffects": false +} diff --git a/packages/http-fetch/src/body/blob.ts b/packages/http-fetch/src/body/blob.ts new file mode 100644 index 0000000..0f45844 --- /dev/null +++ b/packages/http-fetch/src/body/blob.ts @@ -0,0 +1,6 @@ +export function blobBody (blob: Blob, headers: Headers): ReadableStream { + headers.set('Content-Length', `${blob.size}`) + headers.set('Content-Type', (blob.type != null && blob.type !== '') ? blob.type : 'application/octet-stream') + + return blob.stream() +} diff --git a/packages/http-fetch/src/body/bytes.ts b/packages/http-fetch/src/body/bytes.ts new file mode 100644 index 0000000..1b0d79c --- /dev/null +++ b/packages/http-fetch/src/body/bytes.ts @@ -0,0 +1,13 @@ +import { toUint8Array } from '@libp2p/http-utils' + +export function bytesBody (bytes: Uint8Array, headers: Headers): ReadableStream { + headers.set('Content-Length', `${bytes.byteLength}`) + headers.set('Content-Type', 'application/octet-stream') + + return new ReadableStream({ + start (controller) { + controller.enqueue(toUint8Array(bytes)) + controller.close() + } + }) +} diff --git a/packages/http-fetch/src/body/form-data.ts b/packages/http-fetch/src/body/form-data.ts new file mode 100644 index 0000000..2ba32fe --- /dev/null +++ b/packages/http-fetch/src/body/form-data.ts @@ -0,0 +1,116 @@ +import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' + +function calculateSize (name: string, entry: FormDataEntryValue, boundary: string): number { + const header = [ + `--${boundary}` + ] + + let contentLength = 0 + const trailingLinebreak = '\r\n'.length + + if (typeof entry === 'string') { + header.push( + `Content-Disposition: form-data; name="${name}"`, + 'Content-Type: text/plain; charset="UTF-8"', + `Content-Length: ${entry.length}`, + '' + ) + + contentLength = entry.length + trailingLinebreak + } else { + header.push( + `Content-Disposition: form-data; name="${name}"; filename="${encodeURIComponent(entry.name)}"`, + 'Content-Type: application/octet-stream', + `Content-Length: ${entry.size}`, + '' + ) + + contentLength = entry.size + trailingLinebreak + } + + const buf = uint8arrayFromString(header.join('\r\n')) + + return buf.byteLength + contentLength +} + +export function formDataBody (formData: FormData, headers: Headers): ReadableStream { + const boundary = `-----------------------------${crypto.randomUUID()}` + headers.set('Content-Type', `multipart/form-data; boundary=${boundary}`) + + // calculate length + let length = 0 + for (const [name, value] of formData.entries()) { + length += calculateSize(name, value, boundary) + } + + headers.set('Content-Length', `${length}`) + + const formDataIterator = formData.entries() + let fileDataReader: ReadableStreamDefaultReader | undefined + + function queuePart (controller: ReadableStreamDefaultController, name: string, entry: FormDataEntryValue, boundary: string): void { + const header = [ + `--${boundary}` + ] + + if (typeof entry === 'string') { + header.push( + `Content-Disposition: form-data; name="${name}"`, + 'Content-Type: text/plain; charset="UTF-8"', + `Content-Length: ${entry.length}`, + '', + entry, + '' + ) + } else { + header.push( + `Content-Disposition: form-data; name="${name}"; filename="${encodeURIComponent(entry.name)}"`, + 'Content-Type: application/octet-stream', + `Content-Length: ${entry.size}`, + '' + ) + + // write header this time, next time read file data + fileDataReader = entry.stream().getReader() + } + + controller.enqueue(uint8arrayFromString(header.join('\r\n'))) + } + + async function getNext (controller: ReadableStreamDefaultController, boundary: string): Promise { + // check if we are part way through reading a File entry + if (fileDataReader != null) { + const result = await fileDataReader.read() + + if (result.value != null) { + controller.enqueue(result.value) + } + + if (result.done) { + controller.enqueue(uint8arrayFromString('\r\n')) + fileDataReader = undefined + } + + return + } + + // read next FormData field + const { done, value } = formDataIterator.next() + + if (value != null) { + const [name, entry] = value + + queuePart(controller, name, entry, boundary) + } + + if (done === true) { + controller.close() + } + } + + return new ReadableStream({ + async pull (controller): Promise { + await getNext(controller, boundary) + } + }) +} diff --git a/packages/http-fetch/src/body/readable-stream.ts b/packages/http-fetch/src/body/readable-stream.ts new file mode 100644 index 0000000..7c73db4 --- /dev/null +++ b/packages/http-fetch/src/body/readable-stream.ts @@ -0,0 +1,26 @@ +import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' + +export function readableStreamBody (stream: ReadableStream, headers: Headers): ReadableStream { + headers.set('Content-Type', 'application/octet-stream') + headers.set('Transfer-Encoding', 'chunked') + + const reader = stream.getReader() + + return new ReadableStream({ + async pull (controller) { + const { done, value } = await reader.read() + + if (value != null) { + controller.enqueue(uint8arrayFromString(`${value.byteLength}\r\n`)) + controller.enqueue(value) + controller.enqueue(uint8arrayFromString('\r\n')) + } + + if (done) { + // write the final chunk + controller.enqueue(uint8arrayFromString('0\r\n\r\n')) + controller.close() + } + } + }) +} diff --git a/packages/http-fetch/src/body/string.ts b/packages/http-fetch/src/body/string.ts new file mode 100644 index 0000000..748d758 --- /dev/null +++ b/packages/http-fetch/src/body/string.ts @@ -0,0 +1,13 @@ +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' + +export function stringBody (str: string, headers: Headers): ReadableStream { + headers.set('Content-Length', `${str.length}`) + headers.set('Content-Type', 'text/plain; charset="UTF-8"') + + return new ReadableStream({ + start (controller) { + controller.enqueue(uint8ArrayFromString(str)) + controller.close() + } + }) +} diff --git a/packages/http-fetch/src/errors.ts b/packages/http-fetch/src/errors.ts new file mode 100644 index 0000000..0587eec --- /dev/null +++ b/packages/http-fetch/src/errors.ts @@ -0,0 +1,4 @@ +export class InvalidResponseError extends Error { + static name = 'InvalidResponseError' + name = 'InvalidResponseError' +} diff --git a/packages/http-fetch/src/index.ts b/packages/http-fetch/src/index.ts new file mode 100644 index 0000000..66b1339 --- /dev/null +++ b/packages/http-fetch/src/index.ts @@ -0,0 +1,45 @@ +/** + * @packageDocumentation + * + * This is an implementation of the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) + * that uses libp2p streams as the underlying transport layer, instead of a TCP + * socket. + */ + +import { byteStream } from 'it-byte-stream' +import { readResponse } from './read-response.js' +import { sendRequest } from './send-request.js' +import type { ComponentLogger, Logger, Stream } from '@libp2p/interface' + +export interface FetchInit extends RequestInit { + logger: ComponentLogger + + /** + * The maximum number of bytes that will be parsed as headers, defaults to + * 80KB + * + * @default 81_920 + */ + maxHeaderSize?: number +} + +export interface SendRequestInit extends RequestInit { + log: Logger + maxHeaderSize?: number +} + +export async function fetch (stream: Stream, resource: string | URL, init: FetchInit): Promise { + const log = init.logger.forComponent('libp2p:http:fetch') + resource = typeof resource === 'string' ? new URL(resource) : resource + const bytes = byteStream(stream) + + await sendRequest(bytes, resource, { + ...init, + log + }) + + return readResponse(bytes, resource, { + ...init, + log + }) +} diff --git a/packages/http-fetch/src/read-response.ts b/packages/http-fetch/src/read-response.ts new file mode 100644 index 0000000..a162831 --- /dev/null +++ b/packages/http-fetch/src/read-response.ts @@ -0,0 +1,98 @@ +import { HTTPParser } from '@achingbrain/http-parser-js' +import { Response } from '@libp2p/http-utils' +import { InvalidResponseError } from './errors.js' +import type { SendRequestInit } from './index.js' +import type { Stream } from '@libp2p/interface' +import type { ByteStream } from 'it-byte-stream' + +const nullBodyStatus = [101, 204, 205, 304] + +export async function readResponse (bytes: ByteStream, resource: URL, init: SendRequestInit): Promise { + return new Promise((resolve, reject) => { + const body = new TransformStream() + const writer = body.writable.getWriter() + let headersComplete = false + + const parser = new HTTPParser('RESPONSE') + parser.maxHeaderSize = init.maxHeaderSize ?? HTTPParser.maxHeaderSize + parser[HTTPParser.kOnHeadersComplete] = (info) => { + init.log('response headers complete') + headersComplete = true + const headers = new Headers() + + for (let i = 0; i < info.headers.length; i += 2) { + headers.append(info.headers[i], info.headers[i + 1]) + } + + let responseBody: BodyInit | null = body.readable + + if (nullBodyStatus.includes(info.statusCode)) { + body.writable.close().catch(() => {}) + body.readable.cancel().catch(() => {}) + responseBody = null + } + + const response = new Response(responseBody, { + status: info.statusCode, + statusText: info.statusMessage, + headers + }) + + resolve(response) + } + parser[HTTPParser.kOnBody] = (buf) => { + init.log('response read body %d bytes', buf.byteLength) + writer.write(buf) + .catch((err: Error) => { + reject(err) + }) + } + parser[HTTPParser.kOnMessageComplete] = () => { + init.log('response message complete') + writer.close() + .catch((err: Error) => { + reject(err) + }) + + const stream = bytes.unwrap() + stream.close() + .catch(err => { + stream.abort(err) + }) + } + + Promise.resolve() + .then(async () => { + let read = 0 + while (true) { + init.log('reading response') + const chunk = await bytes.read({ + signal: init.signal ?? undefined + }) + + if (chunk == null) { + const err = parser.finish() + + if (err != null) { + init.log('response stream ended with error - %e', err) + } else { + init.log('response stream ended') + } + + if (!headersComplete) { + reject(new InvalidResponseError(`Response ended before headers were received, read ${read} bytes`)) + } + + break + } + + init.log('response stream read %d bytes', chunk.byteLength) + read += chunk.byteLength + parser.execute(chunk.subarray(), 0, chunk.byteLength) + } + }) + .catch((err: Error) => { + reject(err) + }) + }) +} diff --git a/packages/http-fetch/src/send-request.ts b/packages/http-fetch/src/send-request.ts new file mode 100644 index 0000000..b448884 --- /dev/null +++ b/packages/http-fetch/src/send-request.ts @@ -0,0 +1,55 @@ +import { writeHeaders } from '@libp2p/http-utils' +import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' +import { normalizeContent } from './utils.js' +import type { SendRequestInit } from './index.js' +import type { Stream } from '@libp2p/interface' +import type { ByteStream } from 'it-byte-stream' + +export async function sendRequest (bytes: ByteStream, url: URL, init: SendRequestInit): Promise { + const headers = new Headers(init.headers) + + const host = headers.get('host') ?? url.hostname + headers.set('host', host) + + if (headers.get('user-agent') == null) { + headers.set('user-agent', 'libp2p/fetch') + } + + const content = normalizeContent(init.body, headers) + + const req = [ + `${init?.method?.toUpperCase() ?? 'GET'} ${url.pathname ?? '/'} HTTP/1.1`, + ...writeHeaders(headers), + '', + '' + ] + + await bytes.write(uint8arrayFromString(req.join('\r\n')), { + signal: init.signal ?? undefined + }) + + if (content != null) { + init.log('request sending body') + await sendBody(bytes, content, init) + } +} + +async function sendBody (bytes: ByteStream, stream: ReadableStream, init: SendRequestInit): Promise { + const reader = stream.getReader() + + while (true) { + const { done, value } = await reader.read() + + if (value != null) { + init.log('request send %d bytes', value.byteLength) + await bytes.write(value, { + signal: init.signal ?? undefined + }) + } + + if (done) { + init.log('request finished sending body') + break + } + } +} diff --git a/packages/http-fetch/src/utils.ts b/packages/http-fetch/src/utils.ts new file mode 100644 index 0000000..1c7611b --- /dev/null +++ b/packages/http-fetch/src/utils.ts @@ -0,0 +1,35 @@ +import { blobBody } from './body/blob.js' +import { bytesBody } from './body/bytes.js' +import { formDataBody } from './body/form-data.js' +import { readableStreamBody } from './body/readable-stream.js' +import { stringBody } from './body/string.js' + +export function normalizeContent (body: BodyInit | null | undefined, headers: Headers): ReadableStream | undefined { + if (body == null) { + return + } + + if (typeof body === 'string') { + return stringBody(body, headers) + } else if (body instanceof Blob) { + return blobBody(body, headers) + } else if (isBytes(body)) { + return bytesBody(body, headers) + } else if (body instanceof URLSearchParams) { + return stringBody(body.toString(), headers) + } else if (body instanceof ReadableStream) { + return readableStreamBody(body, headers) + } else if (body instanceof FormData) { + return formDataBody(body, headers) + } + + throw new Error('Unsupported body type') +} + +function isBytes (obj?: any): obj is Uint8Array { + if (obj == null) { + return false + } + + return obj.byteLength != null +} diff --git a/test/fetch/cases/cases.js b/packages/http-fetch/test/fixtures/cases.ts similarity index 99% rename from test/fetch/cases/cases.js rename to packages/http-fetch/test/fixtures/cases.ts index 4b48df1..45185a8 100644 --- a/test/fetch/cases/cases.js +++ b/packages/http-fetch/test/fixtures/cases.ts @@ -1,4 +1,5 @@ /* eslint-disable */ +/* spell-checker: disable */ // cases from https://github.com/creationix/http-parser-js var CRLF = '\r\n'; diff --git a/packages/http-fetch/test/index.spec.ts b/packages/http-fetch/test/index.spec.ts new file mode 100644 index 0000000..e47a206 --- /dev/null +++ b/packages/http-fetch/test/index.spec.ts @@ -0,0 +1,172 @@ +/* eslint-env mocha */ + +import { readHeaders, responseToStream, streamToRequest } from '@libp2p/http-utils' +import { defaultLogger } from '@libp2p/logger' +import { expect } from 'aegir/chai' +import drain from 'it-drain' +import { duplexPair } from 'it-pair/duplex' +import { stubInterface } from 'sinon-ts' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { fetch } from '../src/index.js' +import { cases } from './fixtures/cases.js' +import type { Stream } from '@libp2p/interface' + +function serve (server: any, handler: (req: Request) => Response | Promise): void { + const stream = stubInterface({ + ...server, + closeWrite: async () => {} + }) + + void Promise.resolve().then(async () => { + const info = await readHeaders(stream) + const res = await handler(streamToRequest(info, stream)) + await responseToStream(res, stream) + }) +} + +function echo (server: any): void { + serve(server, (req) => { + return new Response(req.body, { + headers: req.headers + }) + }) +} + +describe('@libp2p/http-fetch', () => { + it('should make a simple GET request', async () => { + const [client, server] = duplexPair() + + serve(server, (req) => { + return new Response('Hello World') + }) + + const res = await fetch(stubInterface(client), 'https://example.com', { + logger: defaultLogger() + }) + + expect(await res.text()).to.equal('Hello World') + }) + + it('should GET with headers', async () => { + const [client, server] = duplexPair() + + echo(server) + + const res = await fetch(stubInterface(client), 'https://example.com', { + logger: defaultLogger(), + headers: { + 'X-Test': 'foo' + } + }) + + expect(res.headers.get('X-Test')).to.equal('foo') + }) + + it('should POST some data', async () => { + const [client, server] = duplexPair() + + echo(server) + + const res = await fetch(stubInterface(client), 'https://example.com', { + logger: defaultLogger(), + method: 'POST', + body: 'Hello World' + }) + + expect(await res.text()).to.equal('Hello World') + }) + + it('should handle trash', async () => { + const [client, server] = duplexPair() + + void server.sink([uint8ArrayFromString('FOOOOOOOOOOOOOOOOo')]) + void drain(server.source) + + await expect(fetch(stubInterface(client), 'https://example.com', { + logger: defaultLogger() + })).to.eventually.be.rejected() + .with.property('name', 'InvalidResponseError') + }) + + it('should handle messages that arrive in a trickle', async () => { + for (const httpCase of cases.filter(c => c.type === 'RESPONSE' && c.mayFail !== true)) { + const expectedStatusCode = httpCase.statusCode + + if (expectedStatusCode === undefined || expectedStatusCode === null) { + continue + } + + if (expectedStatusCode < 200 || expectedStatusCode >= 600) { + // Response object doesn't parse these + continue + } + + if (httpCase?.httpMajor !== 1 || httpCase?.httpMinor !== 1) { + // We don't use anything but HTTP/1.1 + continue + } + + const [client, server] = duplexPair() + + void server.sink((async function * () { + const rawHttp = new TextEncoder().encode(httpCase.raw) + // Trickle the response 1 byte at a time + for (let i = 0; i < rawHttp.length; i++) { + yield rawHttp.subarray(i, i + 1) + } + })()) + void drain(server.source) + + // Request doesn't matter + const resp = await fetch(stubInterface(client), 'https://example.com', { + logger: defaultLogger() + }) + + expect(resp.status).to.equal(expectedStatusCode) + const chunk = (arr: T[], size: number): T[][] => arr.reduce((chunks, el, i) => i % size === 0 ? [...chunks, [el]] : (chunks[chunks.length - 1].push(el), chunks), []) + for (const [key, value] of chunk(httpCase.headers, 2)) { + expect(resp.headers.get(key)).to.equal(value) + } + + expect(await resp.text()).to.equal(httpCase.body ?? '') + } + }) + + it('Parses all responses', async () => { + for (const httpCase of cases.filter(c => c.type === 'RESPONSE' && c.mayFail !== true)) { + const expectedStatusCode = httpCase.statusCode + + if (expectedStatusCode === undefined || expectedStatusCode === null) { + continue + } + + if (expectedStatusCode < 200 || expectedStatusCode >= 600) { + // Response object doesn't parse these + continue + } + + if (httpCase?.httpMajor !== 1 || httpCase?.httpMinor !== 1) { + // We don't use anything but HTTP/1.1 + continue + } + + const [client, server] = duplexPair() + + void server.sink([uint8ArrayFromString(httpCase.raw)]) + void drain(server.source) + + // Request doesn't matter + const resp = await fetch(stubInterface(client), 'https://example.com', { + logger: defaultLogger() + }) + + expect(resp.status).to.equal(expectedStatusCode) + const chunk = (arr: T[], size: number): T[][] => arr.reduce((chunks, el, i) => i % size === 0 ? [...chunks, [el]] : (chunks[chunks.length - 1].push(el), chunks), []) + for (const [key, value] of chunk(httpCase.headers, 2)) { + expect(resp.headers.get(key)).to.equal(value) + } + + expect(await resp.text()).to.equal(httpCase.body ?? '') + } + }) +}) diff --git a/packages/http-fetch/tsconfig.json b/packages/http-fetch/tsconfig.json new file mode 100644 index 0000000..7cfc2d8 --- /dev/null +++ b/packages/http-fetch/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ], + "references": [ + { + "path": "../http-utils" + } + ] +} diff --git a/packages/http-fetch/typedoc.json b/packages/http-fetch/typedoc.json new file mode 100644 index 0000000..db0b074 --- /dev/null +++ b/packages/http-fetch/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/packages/http-peer-id-auth/CODE_OF_CONDUCT.md b/packages/http-peer-id-auth/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b0fa54 --- /dev/null +++ b/packages/http-peer-id-auth/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/packages/http-peer-id-auth/LICENSE-APACHE b/packages/http-peer-id-auth/LICENSE-APACHE new file mode 100644 index 0000000..b09cd78 --- /dev/null +++ b/packages/http-peer-id-auth/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/packages/http-peer-id-auth/LICENSE-MIT b/packages/http-peer-id-auth/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/http-peer-id-auth/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/packages/http-peer-id-auth/README.md b/packages/http-peer-id-auth/README.md new file mode 100644 index 0000000..6e3c026 --- /dev/null +++ b/packages/http-peer-id-auth/README.md @@ -0,0 +1,59 @@ +# @libp2p/http-client + +# @libp2p/http-peer-id-auth + +[![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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> An implementation of Peer ID Authentication over HTTP + +# About + + + +This is an implementation of the [Peer ID Auth](https://github.com/libp2p/specs/blob/master/http/peer-id-auth.md) +spec that allows clients and servers to exchange PeerIds. + +# Install + +```console +$ npm i @libp2p/http-peer-id-auth +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-peer-id-auth/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-peer-id-auth/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/packages/http-peer-id-auth/package.json b/packages/http-peer-id-auth/package.json new file mode 100644 index 0000000..97f814c --- /dev/null +++ b/packages/http-peer-id-auth/package.json @@ -0,0 +1,152 @@ +{ + "name": "@libp2p/http-peer-id-auth", + "version": "0.0.0", + "description": "An implementation of Peer ID Authentication over HTTP", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-peer-id-auth#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/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" + } + }, + "release": { + "branches": [ + "main" + ], + "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": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check", + "release": "aegir release" + }, + "dependencies": { + "@libp2p/crypto": "^5.1.4", + "@libp2p/interface": "^2.10.2", + "@libp2p/peer-id": "^5.1.5", + "@multiformats/multiaddr": "^12.4.0", + "uint8-varint": "^2.0.4", + "uint8arrays": "^5.1.0" + }, + "devDependencies": { + "aegir": "^47.0.16" + }, + "sideEffects": false +} diff --git a/packages/http-peer-id-auth/src/client.ts b/packages/http-peer-id-auth/src/client.ts new file mode 100644 index 0000000..f963c6f --- /dev/null +++ b/packages/http-peer-id-auth/src/client.ts @@ -0,0 +1,322 @@ +import { publicKeyFromProtobuf, publicKeyToProtobuf } from '@libp2p/crypto/keys' +import { InvalidMessageError } from '@libp2p/interface' +import { peerIdFromPublicKey } from '@libp2p/peer-id' +import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' +import { InvalidPeerError, InvalidSignatureError, InvalidStateError } from './errors.js' +import { decodeAuthorizationHeader, encodeAuthParams, generateChallenge, sign, verify } from './utils.js' +import { PEER_ID_AUTH_SCHEME } from './index.js' +import type { BearerTokenHeader, ClientChallengeResponseHeader, ClientResponse, ServerChallengeHeader, VerifyClientChallengeResponseOptions, VerifyPeer } from './index.js' +import type { PeerId, PrivateKey, PublicKey } from '@libp2p/interface' +import type { AbortOptions } from '@multiformats/multiaddr' + +export function isClientChallengeResponse (obj?: any): obj is ClientChallengeResponseHeader { + if (obj == null) { + return false + } + + return typeof obj['challenge-client'] === 'string' && + typeof obj['public-key'] === 'string' && + typeof obj.sig === 'string' && + typeof obj.opaque === 'string' +} + +export function isServerChallenge (obj?: any): obj is ServerChallengeHeader { + if (obj == null) { + return false + } + + return typeof obj['challenge-client'] === 'string' && + typeof obj['public-key'] === 'string' && + typeof obj.opaque === 'string' +} + +export function isBearerToken (obj: any): obj is BearerTokenHeader { + if (obj == null) { + return false + } + + return typeof obj.bearer === 'string' +} + +/** + * Verify the response to the client challenge created by + * `createClientChallenge` + */ +export async function verifyClientChallengeResponse (authHeader: ClientChallengeResponseHeader, hostname: string, clientKey: PrivateKey, opts: VerifyClientChallengeResponseOptions = {}): Promise { + const serverPubKeyBytes = uint8ArrayFromString(authHeader['public-key'], 'base64urlpad') + const serverPublicKey = publicKeyFromProtobuf(serverPubKeyBytes) + const marshalledClientPubKey = publicKeyToProtobuf(clientKey.publicKey) + + const valid = await verify(serverPublicKey, PEER_ID_AUTH_SCHEME, [ + ['hostname', hostname], + ['client-public-key', marshalledClientPubKey], + ['challenge-server', authHeader['challenge-client']]], + uint8ArrayFromString(authHeader.sig, 'base64urlpad') + ) + + if (!valid) { + throw new InvalidSignatureError('Invalid signature') + } + + const serverID = peerIdFromPublicKey(serverPublicKey) + + if ((await opts.verifyPeer?.(serverID, opts)) === false) { + throw new InvalidPeerError('verifyPeer check failed') + } + + const sig = await sign(clientKey, PEER_ID_AUTH_SCHEME, [ + ['hostname', hostname], + ['server-public-key', serverPubKeyBytes], + ['challenge-client', authHeader['challenge-client']]]) + + return { + peerId: serverID, + authenticate: encodeAuthParams({ + opaque: authHeader.opaque, + sig: uint8ArrayToString(sig, 'base64urlpad') + }) + } +} + +export async function respondToServerChallenge (serverChallenge: ServerChallengeHeader, hostname: string, clientKey: PrivateKey): Promise { + const serverPublicKey = publicKeyFromProtobuf(uint8ArrayFromString(serverChallenge['public-key'], 'base64urlpad')) + const serverPeerId = peerIdFromPublicKey(serverPublicKey) + + // sign and return challenge + const sig = await sign(clientKey, PEER_ID_AUTH_SCHEME, [ + ['hostname', hostname], + ['server-public-key', publicKeyToProtobuf(serverPublicKey)], + ['challenge-client', serverChallenge['challenge-client']] + ]) + + return { + peerId: serverPeerId, + authenticate: encodeAuthParams({ + 'challenge-server': serverChallenge['challenge-client'], + 'public-key': uint8ArrayToString(publicKeyToProtobuf(clientKey.publicKey), 'base64urlpad'), + sig: uint8ArrayToString(sig, 'base64urlpad'), + opaque: serverChallenge.opaque + }) + } +} + +export async function decodeBearerToken (authHeader: BearerTokenHeader, clientKey: PrivateKey, challenge: string, hostname: string, serverPublicKey: PublicKey): Promise { + if (authHeader.sig != null) { + const marshalledClientPubKey = publicKeyToProtobuf(clientKey.publicKey) + const valid = await verify(serverPublicKey, PEER_ID_AUTH_SCHEME, [ + ['challenge-server', challenge], + ['client-public-key', marshalledClientPubKey], + ['hostname', hostname]], + uint8ArrayFromString(authHeader.sig, 'base64urlpad') + ) + + if (!valid) { + throw new InvalidSignatureError('Invalid signature') + } + } + + return authHeader.bearer +} + +type HandshakeState = 'init' | 'challenge-server' | 'verify-server' | 'respond-to-server' | 'complete' + +export class ClientInitiatedHandshake { + private readonly clientKey: PrivateKey + private readonly challenge: string + private readonly hostname: string + private readonly verifyPeer?: VerifyPeer + private state: HandshakeState + public serverId?: PeerId + public bearer?: string + + constructor (clientKey: PrivateKey, hostname: string, verifyPeer?: VerifyPeer) { + this.state = 'init' + this.clientKey = clientKey + this.challenge = generateChallenge() + this.hostname = hostname + this.verifyPeer = verifyPeer + } + + /** + * Step 1, send the server a challenge + */ + getChallenge (): string { + this.state = 'challenge-server' + + return encodeAuthParams({ + 'challenge-server': this.challenge, + 'public-key': uint8ArrayToString(publicKeyToProtobuf(this.clientKey.publicKey), 'base64urlpad') + }) + } + + /** + * Step 2, verify the server response, and answer the server challenge + */ + async verifyServer (header: string, opts?: AbortOptions): Promise { + if (this.state !== 'challenge-server') { + throw new InvalidStateError(`Client Initiated Handshake state was "${this.state}" and not "challenge-server"`) + } + + const message = decodeAuthorizationHeader(header) + + if (!isClientChallengeResponse(message)) { + throw new InvalidMessageError('Server sent incorrect message') + } + + this.state = 'verify-server' + + const serverPubKeyBytes = uint8ArrayFromString(message['public-key'], 'base64urlpad') + const serverPublicKey = publicKeyFromProtobuf(serverPubKeyBytes) + const marshalledClientPubKey = publicKeyToProtobuf(this.clientKey.publicKey) + + const valid = await verify(serverPublicKey, PEER_ID_AUTH_SCHEME, [ + ['challenge-server', this.challenge], + ['client-public-key', marshalledClientPubKey], + ['hostname', this.hostname] + ], uint8ArrayFromString(message.sig, 'base64urlpad')) + + if (!valid) { + throw new InvalidSignatureError('Invalid signature') + } + + this.serverId = peerIdFromPublicKey(serverPublicKey) + + if ((await this.verifyPeer?.(this.serverId, opts)) === false) { + throw new InvalidPeerError('verifyPeer check failed') + } + + const sig = await sign(this.clientKey, PEER_ID_AUTH_SCHEME, [ + ['hostname', this.hostname], + ['server-public-key', serverPubKeyBytes], + ['challenge-client', message['challenge-client']]]) + + this.state = 'respond-to-server' + + return encodeAuthParams({ + opaque: message.opaque, + sig: uint8ArrayToString(sig, 'base64urlpad') + }) + } + + /** + * Step 3, decode the bearer token sent by the server + */ + decodeBearerToken (header: string): string { + if (this.state !== 'respond-to-server') { + throw new InvalidStateError(`Client Initiated Handshake state was "${this.state}" and not "respond-to-server"`) + } + + const message = decodeAuthorizationHeader(header) + + if (!isBearerToken(message)) { + throw new InvalidMessageError('Server sent incorrect message') + } + + this.state = 'complete' + this.bearer = message.bearer + + return encodeAuthParams({ + bearer: this.bearer + }) + } +} + +export class ServerInitiatedHandshake { + private readonly clientKey: PrivateKey + private readonly hostname: string + private readonly verifyPeer?: VerifyPeer + private state: HandshakeState + public serverId?: PeerId + public bearer?: string + private serverPublicKey?: PublicKey + private challenge?: string + + constructor (clientKey: PrivateKey, hostname: string, verifyPeer?: VerifyPeer) { + this.state = 'init' + this.clientKey = clientKey + this.hostname = hostname + this.verifyPeer = verifyPeer + } + + /** + * Step 1 respond to the server challenge and issue our own challenge + */ + async answerServerChallenge (header: string, opts?: AbortOptions): Promise { + if (this.state !== 'init') { + throw new InvalidStateError(`Client Initiated Handshake state was "${this.state}" and not "init"`) + } + + const message = decodeAuthorizationHeader(header) + + if (!isServerChallenge(message)) { + throw new InvalidMessageError('Server sent incorrect message') + } + + this.state = 'verify-server' + + this.serverPublicKey = publicKeyFromProtobuf(uint8ArrayFromString(message['public-key'], 'base64urlpad')) + this.serverId = peerIdFromPublicKey(this.serverPublicKey) + this.challenge = message['challenge-client'] + + // sign and return challenge + const sig = await sign(this.clientKey, PEER_ID_AUTH_SCHEME, [ + ['hostname', this.hostname], + ['server-public-key', publicKeyToProtobuf(this.serverPublicKey)], + ['challenge-client', message['challenge-client']] + ]) + + if ((await this.verifyPeer?.(this.serverId, opts)) === false) { + throw new InvalidPeerError('verifyPeer check failed') + } + + this.state = 'challenge-server' + + return encodeAuthParams({ + 'challenge-server': message['challenge-client'], + 'public-key': uint8ArrayToString(publicKeyToProtobuf(this.clientKey.publicKey), 'base64urlpad'), + sig: uint8ArrayToString(sig, 'base64urlpad'), + opaque: message.opaque + }) + } + + /** + * Step 2, verify the server response and extract the bearer token + */ + async decodeBearerToken (header: string): Promise { + if (this.state !== 'challenge-server') { + throw new InvalidStateError(`Client Initiated Handshake state was "${this.state}" and not "challenge-server"`) + } + + const message = decodeAuthorizationHeader(header) + + if (!isBearerToken(message)) { + throw new InvalidMessageError('Server sent incorrect message') + } + + if (message.sig == null) { + throw new InvalidMessageError('Server sent incorrect message') + } + + if (this.serverPublicKey == null || this.challenge == null) { + throw new InvalidStateError('Server public key and/or challenge missing') + } + + const valid = await verify(this.serverPublicKey, PEER_ID_AUTH_SCHEME, [ + ['hostname', this.hostname], + ['client-public-key', publicKeyToProtobuf(this.clientKey.publicKey)], + ['challenge-server', this.challenge]], + uint8ArrayFromString(message.sig, 'base64urlpad') + ) + + if (!valid) { + throw new InvalidSignatureError('Invalid signature') + } + + this.state = 'complete' + this.bearer = message.bearer + + return encodeAuthParams({ + bearer: this.bearer + }) + } +} diff --git a/src/auth/errors.ts b/packages/http-peer-id-auth/src/errors.ts similarity index 66% rename from src/auth/errors.ts rename to packages/http-peer-id-auth/src/errors.ts index c46d071..17fe4a5 100644 --- a/src/auth/errors.ts +++ b/packages/http-peer-id-auth/src/errors.ts @@ -17,3 +17,13 @@ export class BadResponseError extends Error { static name = 'BadResponseError' name = 'BadResponseError' } + +export class NotAuthenticatedError extends Error { + static name = 'NotAuthenticatedError' + name = 'NotAuthenticatedError' +} + +export class InvalidStateError extends Error { + static name = 'InvalidStateError' + name = 'InvalidStateError' +} diff --git a/packages/http-peer-id-auth/src/index.ts b/packages/http-peer-id-auth/src/index.ts new file mode 100644 index 0000000..e57110a --- /dev/null +++ b/packages/http-peer-id-auth/src/index.ts @@ -0,0 +1,152 @@ +/** + * @packageDocumentation + * + * This is an implementation of the [Peer ID Auth](https://github.com/libp2p/specs/blob/master/http/peer-id-auth.md) + * spec that allows clients and servers to exchange PeerIds. + */ + +import { publicKeyToProtobuf } from '@libp2p/crypto/keys' +import { InvalidMessageError } from '@libp2p/interface' +import { toString as uint8ArrayToString } from 'uint8arrays' +import { isClientChallenge, isOpaqueData, isServerChallengeResponse, issueBearerToken, respondToClientChallenge, respondToServerChallengeResponse, unwrapBearerToken } from './server.js' +import { decodeAuthorizationHeader, encodeAuthParams, generateChallenge, genOpaque } from './utils.js' +import type { AbortOptions, PeerId, PrivateKey } from '@libp2p/interface' + +export * from './errors.js' + +export const PEER_ID_AUTH_SCHEME = 'libp2p-PeerID' +export const HTTP_PEER_ID_AUTH_PROTOCOL = '/http-peer-id-auth/1.0.0' +export const DEFAULT_AUTH_TOKEN_TTL = 60 * 60 * 1000 // 1 hour + +export interface ClientChallengeHeader { + 'challenge-server': string + 'public-key': string +} + +export interface ClientChallengeResponseHeader { + 'challenge-client': string + 'public-key': string + sig: string + opaque: string +} + +export interface BearerTokenHeader { + bearer: string + sig?: string +} + +export interface OpaqueDataHeader { + opaque: string + sig: string +} + +export interface ServerChallengeHeader { + 'challenge-client': string + 'public-key': string + opaque: string +} + +export interface ServerChallengeResponseHeader { + 'challenge-server': string + 'public-key': string + opaque: string + sig: string +} + +function isBearerToken (obj: any): obj is BearerTokenHeader { + if (obj == null) { + return false + } + + return typeof obj.bearer === 'string' +} + +export interface ServerResponse { + /** + * The PeerId of the client + */ + peerId: PeerId + + /** + * If present this should be sent to the client as a `authentication-info` + * header + */ + info?: string + + /** + * If present this should be sent to the client as a `www-authenticate` header + */ + authenticate?: string +} + +export interface ClientResponse { + /** + * The PeerId of the server + */ + peerId: PeerId + + /** + * If present this should be sent to the client as a `www-authenticate` header + */ + authenticate?: string + + /** + * If present this should be used for subsequent requests + */ + bearer?: string +} + +export interface VerifyPeer { + (peerId: PeerId, opts?: AbortOptions): boolean | Promise +} + +export interface VerifyClientChallengeResponseOptions extends AbortOptions { + verifyPeer?: VerifyPeer + tokenTTL?: number +} + +export async function createServerChallenge (hostname: string, serverKey: PrivateKey): Promise { + const challenge = generateChallenge() + + return encodeAuthParams({ + 'challenge-client': challenge, + 'public-key': uint8ArrayToString(publicKeyToProtobuf(serverKey.publicKey), 'base64urlpad'), + opaque: await genOpaque(serverKey, { + challengeClient: challenge, + hostname, + creationTime: Date.now() + }) + }) +} + +/** + * Handle incoming messages from the authenticating client + */ +export async function serverResponds (authHeader: string, hostname: string, serverKey: PrivateKey, tokenTTL: number = DEFAULT_AUTH_TOKEN_TTL): Promise { + const authFields = decodeAuthorizationHeader(authHeader) + + if (isServerChallengeResponse(authFields)) { + return respondToServerChallengeResponse(authFields, hostname, serverKey) + } + + // client initiates authentication + if (isClientChallenge(authFields)) { + return respondToClientChallenge(authFields, hostname, serverKey) + } + + // client is responding to server challenge + if (isOpaqueData(authFields)) { + return issueBearerToken(authFields, hostname, serverKey, tokenTTL) + } + + // client has previously authenticated + if (isBearerToken(authFields)) { + return { + peerId: await unwrapBearerToken(authFields, hostname, serverKey, tokenTTL) + } + } + + throw new InvalidMessageError('Client sent invalid message') +} + +export { ClientInitiatedHandshake, ServerInitiatedHandshake } from './client.js' diff --git a/packages/http-peer-id-auth/src/server.ts b/packages/http-peer-id-auth/src/server.ts new file mode 100644 index 0000000..7608e56 --- /dev/null +++ b/packages/http-peer-id-auth/src/server.ts @@ -0,0 +1,133 @@ +import { publicKeyFromProtobuf, publicKeyToProtobuf } from '@libp2p/crypto/keys' +import { InvalidMessageError } from '@libp2p/interface' +import { peerIdFromPublicKey, peerIdFromString } from '@libp2p/peer-id' +import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' +import { encodeAuthParams, genBearerToken, genOpaque, generateChallenge, sign, unwrapOpaque, verify, verifyBox } from './utils.js' +import { validateOpaqueData } from './validation.js' +import { DEFAULT_AUTH_TOKEN_TTL, PEER_ID_AUTH_SCHEME } from './index.js' +import type { BearerTokenHeader, ClientChallengeHeader, OpaqueDataHeader, ServerChallengeResponseHeader, ServerResponse } from './index.js' +import type { PeerId, PrivateKey } from '@libp2p/interface' + +export function isClientChallenge (obj: any): obj is ClientChallengeHeader { + if (obj == null) { + return false + } + + return typeof obj['challenge-server'] === 'string' && typeof obj['public-key'] === 'string' +} + +export function isOpaqueData (obj: any): obj is OpaqueDataHeader { + if (obj == null) { + return false + } + + return typeof obj.opaque === 'string' && typeof obj.sig === 'string' +} + +export function isServerChallengeResponse (obj?: any): obj is ServerChallengeResponseHeader { + if (obj == null) { + return false + } + + return typeof obj['challenge-server'] === 'string' && + typeof obj['public-key'] === 'string' && + typeof obj.opaque === 'string' && + typeof obj.sig === 'string' +} + +export async function issueBearerToken (data: OpaqueDataHeader, hostname: string, serverKey: PrivateKey, tokenTTL: number): Promise { + const opaque = await unwrapOpaque(serverKey.publicKey, data) + validateOpaqueData(opaque, hostname, tokenTTL) + + if (opaque.clientPublicKey == null) { + throw new InvalidMessageError('Missing client public key') + } + + const clientPublicKey = publicKeyFromProtobuf(uint8ArrayFromString(opaque.clientPublicKey, 'base64urlpad')) + const clientPeerId = peerIdFromPublicKey(clientPublicKey) + + const valid = await verify(clientPublicKey, PEER_ID_AUTH_SCHEME, [ + ['challenge-client', opaque.challengeClient], + ['hostname', hostname], + ['server-public-key', publicKeyToProtobuf(serverKey.publicKey)] + ], uint8ArrayFromString(data.sig, 'base64urlpad')) + + if (!valid) { + throw new InvalidMessageError('Invalid signature') + } + + // return a bearer token + return { + peerId: clientPeerId, + info: encodeAuthParams({ + bearer: await genBearerToken(serverKey, clientPeerId, hostname) + }) + } +} + +export async function respondToClientChallenge (clientChallenge: ClientChallengeHeader, hostname: string, serverKey: PrivateKey): Promise { + const clientPublicKey = publicKeyFromProtobuf(uint8ArrayFromString(clientChallenge['public-key'], 'base64urlpad')) + const clientPeerId = peerIdFromPublicKey(clientPublicKey) + + // sign and return challenge + const sig = await sign(serverKey, PEER_ID_AUTH_SCHEME, [ + ['challenge-server', clientChallenge['challenge-server']], + ['client-public-key', publicKeyToProtobuf(clientPublicKey)], + ['hostname', hostname] + ]) + + const challenge = generateChallenge() + + return { + peerId: clientPeerId, + authenticate: encodeAuthParams({ + 'challenge-client': challenge, + 'public-key': uint8ArrayToString(publicKeyToProtobuf(serverKey.publicKey), 'base64urlpad'), + sig: uint8ArrayToString(sig, 'base64urlpad'), + opaque: await genOpaque(serverKey, { + challengeClient: challenge, + creationTime: Date.now(), + hostname, + clientPublicKey: clientChallenge['public-key'] + }) + }) + } +} + +export async function respondToServerChallengeResponse (response: ServerChallengeResponseHeader, hostname: string, serverKey: PrivateKey): Promise { + const clientPublicKey = publicKeyFromProtobuf(uint8ArrayFromString(response['public-key'], 'base64urlpad')) + const clientPeerId = peerIdFromPublicKey(clientPublicKey) + + // sign and return challenge + const sig = await sign(serverKey, PEER_ID_AUTH_SCHEME, [ + ['challenge-server', response['challenge-server']], + ['client-public-key', publicKeyToProtobuf(clientPublicKey)], + ['hostname', hostname] + ]) + + return { + peerId: clientPeerId, + info: encodeAuthParams({ + sig: uint8ArrayToString(sig, 'base64urlpad'), + bearer: await genBearerToken(serverKey, clientPeerId, hostname) + }) + } +} + +export async function unwrapBearerToken (token: BearerTokenHeader, expectedHostname: string, privateKey: PrivateKey, tokenTTL: number): Promise { + const unwrapped = await verifyBox(privateKey.publicKey, token.bearer) as any + + if (typeof unwrapped.peer !== 'string' || typeof unwrapped.h !== 'string' || typeof unwrapped.t !== 'number') { + throw new InvalidMessageError('Invalid bearer token') + } + + if (unwrapped.h !== expectedHostname) { + throw new InvalidMessageError('Invalid hostname') + } + + if (Date.now() - unwrapped.t > (tokenTTL ?? DEFAULT_AUTH_TOKEN_TTL)) { + throw new InvalidMessageError('Token expired') + } + + return peerIdFromString(unwrapped.peer) +} diff --git a/packages/http-peer-id-auth/src/utils.ts b/packages/http-peer-id-auth/src/utils.ts new file mode 100644 index 0000000..352add7 --- /dev/null +++ b/packages/http-peer-id-auth/src/utils.ts @@ -0,0 +1,148 @@ +import { InvalidMessageError } from '@libp2p/interface' +import * as varint from 'uint8-varint' +import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' +import { PEER_ID_AUTH_SCHEME } from './index.js' +import type { OpaqueDataHeader } from './index.js' +import type { PeerId, PrivateKey, PublicKey } from '@libp2p/interface' + +export interface OpaqueUnwrapped { + challengeClient: string + clientPublicKey?: string + hostname: string + creationTime: number +} + +export const MAX_AUTH_HEADER_SIZE = 2048 + +export function generateChallenge (): string { + const randomBytes = new Uint8Array(32) + crypto.getRandomValues(randomBytes) + return uint8ArrayToString(randomBytes, 'base64urlpad') +} + +export function encodeAuthParams (params: Record): string { + const encodedParams = Object.entries(params) + .map(([key, value]) => `${key}="${value}"`) + .join(', ') + + return `${PEER_ID_AUTH_SCHEME} ${encodedParams}` +} + +export async function sign (key: PrivateKey, prefix: string, partsToSign: Array<[string, string | Uint8Array]>): Promise { + const dataToSign = genDataToSign(prefix, partsToSign) + return key.sign(dataToSign) +} + +export async function verify (key: PublicKey, prefix: string, partsToSign: Array<[string, string | Uint8Array]>, sig: Uint8Array): Promise { + const dataToSign = genDataToSign(prefix, partsToSign) + return key.verify(dataToSign, sig) +} + +const textEncoder = new TextEncoder() + +function sizeOfPart ([k, v]: [string, string | Uint8Array]): number { + return k.length + 1 + v.length // key + '=' + value +} + +function genDataToSign (prefix: string, partsToSign: Array<[string, string | Uint8Array]>): Uint8Array { + // Sort the parts + partsToSign.sort((a, b) => a[0].localeCompare(b[0])) + + const size = partsToSign.reduce((acc, p) => acc + varint.encodingLength(sizeOfPart(p)) + sizeOfPart(p), prefix.length) + const out = new Uint8Array(size) + let offset = 0 + const res = textEncoder.encodeInto(prefix, out) + offset += res.written + + for (const [k, v] of partsToSign) { + const len = sizeOfPart([k, v]) + varint.encodeUint8Array(len, out, offset) + offset += varint.encodingLength(len) + let res = textEncoder.encodeInto(k, out.subarray(offset)) + offset += res.written + res = textEncoder.encodeInto('=', out.subarray(offset)) + offset += res.written + + if (typeof v === 'string') { + res = textEncoder.encodeInto(v, out.subarray(offset)) + offset += res.written + } else { + out.set(v, offset) + offset += v.length + } + } + + return out +} + +export function decodeAuthorizationHeader (header: string): unknown { + if (header.length < PEER_ID_AUTH_SCHEME.length + 1) { + throw new InvalidMessageError('Authorization header too short') + } + + if (header.length > MAX_AUTH_HEADER_SIZE) { + throw new InvalidMessageError('Authorization header too long') + } + + if (!header.includes(PEER_ID_AUTH_SCHEME)) { + throw new InvalidMessageError('No peer id auth scheme found') + } + + const rest = header.substring(PEER_ID_AUTH_SCHEME.length).trim() + const params: Record = {} + const regex = /(\w[^=]+)="([^"]+)"/g + + let match + while ((match = regex.exec(rest)) !== null) { + params[match[1]] = match[2] + } + + return params +} + +export async function genOpaque (privateKey: PrivateKey, unwrapped: OpaqueUnwrapped): Promise { + return signBox(privateKey, unwrapped) +} + +export async function unwrapOpaque (publicKey: PublicKey, data: OpaqueDataHeader): Promise { + const unwrapped = await verifyBox(publicKey, data.opaque) as any + + if (typeof unwrapped.challengeClient !== 'string' || typeof unwrapped.hostname !== 'string' || typeof unwrapped.creationTime !== 'number') { + throw new Error('Invalid opaque') + } + + return unwrapped +} + +export async function signBox (key: PrivateKey, data: unknown): Promise { + const dataSerialized = JSON.stringify(data) + const dataBytes = uint8ArrayFromString(dataSerialized) + const sig = await key.sign(dataBytes) + const jsonStr = JSON.stringify({ + val: uint8ArrayToString(dataBytes, 'base64urlpad'), + sig: uint8ArrayToString(sig, 'base64urlpad') + }) + + return uint8ArrayToString(uint8ArrayFromString(jsonStr), 'base64urlpad') +} + +export async function verifyBox (key: PublicKey, data: string): Promise { + const { sig, val } = JSON.parse(uint8ArrayToString(uint8ArrayFromString(data, 'base64urlpad'))) + const valBytes = uint8ArrayFromString(val, 'base64urlpad') + const sigValid = await key.verify(valBytes, uint8ArrayFromString(sig, 'base64urlpad')) + + if (!sigValid) { + throw new Error('Invalid signature') + } + + const valStr = uint8ArrayToString(valBytes) + return JSON.parse(valStr) +} + +export async function genBearerToken (serverKey: PrivateKey, clientPeerId: PeerId, hostname: string): Promise { + return signBox(serverKey, { + peer: clientPeerId.toString(), + h: hostname, + t: Date.now() + }) +} diff --git a/packages/http-peer-id-auth/src/validation.ts b/packages/http-peer-id-auth/src/validation.ts new file mode 100644 index 0000000..ae9f2e8 --- /dev/null +++ b/packages/http-peer-id-auth/src/validation.ts @@ -0,0 +1,17 @@ +import { InvalidMessageError } from '@libp2p/interface' +import type { OpaqueUnwrapped } from './utils.js' + +export function validateOpaqueData (opaque: OpaqueUnwrapped, hostname: string, tokenTTL: number): void { + if (opaque.hostname !== hostname) { + throw new InvalidMessageError('Invalid hostname') + } + + // verify signature + if (opaque.challengeClient == null) { + throw new InvalidMessageError('Missing challenge-client') + } + + if (Date.now() - opaque.creationTime > tokenTTL) { + throw new InvalidMessageError('Token expired') + } +} diff --git a/packages/http-peer-id-auth/test/index.spec.ts b/packages/http-peer-id-auth/test/index.spec.ts new file mode 100644 index 0000000..9d799b9 --- /dev/null +++ b/packages/http-peer-id-auth/test/index.spec.ts @@ -0,0 +1,101 @@ +/* eslint-env mocha */ +import { generateKeyPair, privateKeyFromProtobuf } from '@libp2p/crypto/keys' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { expect } from 'aegir/chai' +import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' +import { ClientInitiatedHandshake, ServerInitiatedHandshake } from '../src/client.js' +import { PEER_ID_AUTH_SCHEME, createServerChallenge, serverResponds } from '../src/index.js' +import { sign } from '../src/utils.js' +import type { PeerId, PrivateKey } from '@libp2p/interface' + +describe('@libp2p/http-peer-id-auth', () => { + let init = false + let clientPrivateKey: PrivateKey + let serverPrivateKey: PrivateKey + let serverPeerId: PeerId + let clientPeerId: PeerId + const hostname = 'example.com' + + beforeEach(async () => { + if (!init) { + init = true + clientPrivateKey = await generateKeyPair('Ed25519') + clientPeerId = peerIdFromPrivateKey(clientPrivateKey) + serverPrivateKey = await generateKeyPair('Ed25519') + serverPeerId = peerIdFromPrivateKey(serverPrivateKey) + } + }) + + it('should allow client to initiate authentication', async () => { + const client = new ClientInitiatedHandshake(clientPrivateKey, hostname) + + const clientChallenge = client.getChallenge() + + // server responds to client challenge, issues server challenge + const serverResponse = await serverResponds(clientChallenge, hostname, serverPrivateKey) + expect(serverResponse.peerId).to.deep.equal(clientPeerId) + + if (serverResponse.authenticate == null) { + throw new Error('Server did not challenge client') + } + + // client verifies server response and responds to server challenge + const clientAnswer = await client.verifyServer(serverResponse.authenticate) + + // client responds to the server challenge + const serverResponse2 = await serverResponds(clientAnswer, hostname, serverPrivateKey) + expect(serverResponse2.peerId).to.deep.equal(clientPeerId) + + if (serverResponse2.info == null) { + throw new Error('Server did not issue bearer token') + } + + // read bearer token from response + const bearer = client.decodeBearerToken(serverResponse2.info) + + // use the bearer token for a subsequent request + const serverResponse3 = await serverResponds(bearer, hostname, serverPrivateKey) + expect(serverResponse3.peerId).to.deep.equal(clientPeerId) + + expect(client.serverId).to.deep.equal(serverPeerId) + }) + + it('should allow server to initiate authentication', async () => { + const client = new ServerInitiatedHandshake(clientPrivateKey, hostname) + + const serverChallenge = await createServerChallenge(hostname, serverPrivateKey) + + // client responds to server challenge, issues client challenge + const clientResponse = await client.answerServerChallenge(serverChallenge) + expect(client.serverId).to.deep.equal(serverPeerId) + + // server responds to client challenge, issues bearer token with signature + const serverResponse = await serverResponds(clientResponse, hostname, serverPrivateKey) + expect(serverResponse.peerId).to.deep.equal(clientPeerId) + + if (serverResponse.info == null) { + throw new Error('Server did not issue bearer token') + } + + const bearer = await client.decodeBearerToken(serverResponse.info) + + // use the bearer token for a subsequent request + const serverResponse2 = await serverResponds(bearer, hostname, serverPrivateKey) + expect(serverResponse2.peerId).to.deep.equal(clientPeerId) + }) + + it('should match the test vectors', async () => { + const clientKeyHex = '080112208139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394' + const serverKeyHex = '0801124001010101010101010101010101010101010101010101010101010101010101018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c' + const clientPubKeyEncoded = uint8ArrayFromString(clientKeyHex, 'base16') + const serverKey = privateKeyFromProtobuf(uint8ArrayFromString(serverKeyHex, 'base16')) + + const serverSig = await sign(serverKey, PEER_ID_AUTH_SCHEME, [ + // cspell:disable-next-line + ['challenge-server', 'ERERERERERERERERERERERERERERERERERERERERERE='], + ['client-public-key', clientPubKeyEncoded], + ['hostname', 'example.com'] + ]) + expect(uint8ArrayToString(serverSig, 'base64urlpad')).to.equal('UA88qZbLUzmAxrD9KECbDCgSKAUBAvBHrOCF2X0uPLR1uUCF7qGfLPc7dw3Olo-LaFCDpk5sXN7TkLWPVvuXAA==') + }) +}) diff --git a/tsconfig.json b/packages/http-peer-id-auth/tsconfig.json similarity index 100% rename from tsconfig.json rename to packages/http-peer-id-auth/tsconfig.json diff --git a/packages/http-peer-id-auth/typedoc.json b/packages/http-peer-id-auth/typedoc.json new file mode 100644 index 0000000..db0b074 --- /dev/null +++ b/packages/http-peer-id-auth/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/packages/http-ping/CODE_OF_CONDUCT.md b/packages/http-ping/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b0fa54 --- /dev/null +++ b/packages/http-ping/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/packages/http-ping/LICENSE-APACHE b/packages/http-ping/LICENSE-APACHE new file mode 100644 index 0000000..b09cd78 --- /dev/null +++ b/packages/http-ping/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/packages/http-ping/LICENSE-MIT b/packages/http-ping/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/http-ping/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/packages/http-ping/README.md b/packages/http-ping/README.md new file mode 100644 index 0000000..db76d2d --- /dev/null +++ b/packages/http-ping/README.md @@ -0,0 +1,56 @@ +# @libp2p/http-ping + +[![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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> An HTTP version of the ping protocol + +# About + + + +This is an implementation of a ping protocol that runs over HTTP. + +# Install + +```console +$ npm i @libp2p/http-ping +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-ping/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-ping/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/packages/http-ping/package.json b/packages/http-ping/package.json new file mode 100644 index 0000000..e4b01d8 --- /dev/null +++ b/packages/http-ping/package.json @@ -0,0 +1,152 @@ +{ + "name": "@libp2p/http-ping", + "version": "0.0.0", + "description": "An HTTP version of the ping protocol", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-ping#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/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" + } + }, + "release": { + "branches": [ + "main" + ], + "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": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check", + "release": "aegir release" + }, + "dependencies": { + "@libp2p/http": "~0.0.0", + "@libp2p/interface": "^2.10.2", + "@multiformats/multiaddr": "^12.4.0", + "race-event": "^1.3.0", + "race-signal": "^1.1.3", + "uint8arrays": "^5.1.0" + }, + "devDependencies": { + "aegir": "^47.0.16" + }, + "sideEffects": false +} diff --git a/packages/http-ping/src/index.ts b/packages/http-ping/src/index.ts new file mode 100644 index 0000000..f04bd2f --- /dev/null +++ b/packages/http-ping/src/index.ts @@ -0,0 +1,49 @@ +/** + * @packageDocumentation + * + * This is an implementation of a ping protocol that runs over HTTP. + */ + +import { PingHTTPService as PingHTTPServiceClass } from './ping.js' +import type { HTTP, FetchInit, ConnectInit } from '@libp2p/http' +import type { ComponentLogger, PeerId } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +export const HTTP_PING_PROTOCOL = '/http-ping/1' + +export interface PingHTTPInit { + /** + * The path that the ping protocol will listen on + */ + path?: string + + /** + * Whether authentication is required + * + * @default false + */ + requireAuth?: boolean +} + +export interface PingHTTPComponents { + http: HTTP + logger: ComponentLogger +} + +export interface PingHTTPOptions extends FetchInit { +} + +export interface PingWebSocketOptions extends ConnectInit { + /** + * Make a request over a WebSocket instead of HTTP + */ + webSocket: true +} + +export interface PingHTTP { + ping (peer: string | URL | PeerId | Multiaddr | Multiaddr[], options?: PingHTTPOptions | PingWebSocketOptions): Promise +} + +export function pingHTTP (init: PingHTTPInit = {}): (components: PingHTTPComponents) => PingHTTP { + return (components) => new PingHTTPServiceClass(components, init) +} diff --git a/packages/http-ping/src/ping.ts b/packages/http-ping/src/ping.ts new file mode 100644 index 0000000..66d663e --- /dev/null +++ b/packages/http-ping/src/ping.ts @@ -0,0 +1,159 @@ +import { authenticatedWebSocketRoute } from '@libp2p/http' +import { ProtocolError, serviceDependencies } from '@libp2p/interface' +import { raceEvent } from 'race-event' +import { raceSignal } from 'race-signal' +import { equals as uint8ArrayEquals } from 'uint8arrays/equals' +import { HTTP_PING_PROTOCOL } from './index.js' +import type { PingHTTPComponents, PingHTTPInit, PingHTTP as PingHTTPInterface, PingHTTPOptions, PingWebSocketOptions } from './index.js' +import type { Logger, PeerId, Startable } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +const PING_SIZE = 32 + +export class PingHTTPService implements PingHTTPInterface, Startable { + private readonly components: PingHTTPComponents + private readonly log: Logger + private readonly init: PingHTTPInit + + constructor (components: PingHTTPComponents, init: PingHTTPInit = {}) { + this.components = components + this.log = components.logger.forComponent('libp2p:http:ping') + this.init = init + + this.onHTTPRequest = this.onHTTPRequest.bind(this) + this.onWebSocket = this.onWebSocket.bind(this) + } + + readonly [Symbol.toStringTag] = '@libp2p/ping-http' + + readonly [serviceDependencies]: string[] = [ + '@libp2p/http' + ] + + start (): void { + this.components.http.handle(HTTP_PING_PROTOCOL, authenticatedWebSocketRoute({ + ...this.init, + requireAuth: this.init.requireAuth ?? false, + method: ['GET', 'POST'], + handler: this.onWebSocket, + fallback: this.onHTTPRequest + })) + } + + stop (): void { + this.components.http.unhandle(HTTP_PING_PROTOCOL) + } + + async onHTTPRequest (req: Request): Promise { + this.log('incoming HTTP ping request') + + if (req.body == null) { + this.log.error('body was null') + return new Response(null, { status: 400 }) + } + + const ab = await req.arrayBuffer() + const buf = new Uint8Array(ab, 0, ab.byteLength) + + if (buf.byteLength !== PING_SIZE) { + this.log.error('ping data length was incorrect - expected %d got %d', PING_SIZE, buf.byteLength) + return new Response(null, { status: 400 }) + } + + return new Response(buf, { + headers: { + 'Content-Type': 'application/octet-stream', + 'Content-Length': `${PING_SIZE}` + } + }) + } + + onWebSocket (ws: WebSocket): void { + this.log('incoming WebSocket ping request') + + ws.addEventListener('message', (evt) => { + const buf = new Uint8Array(evt.data, 0, evt.data.byteLength) + + if (buf.length !== PING_SIZE) { + this.log.error('ping data length was incorrect - expected %d got %d', PING_SIZE, buf.byteLength) + ws.close(400) + return + } + + ws.send(buf) + ws.close() + }) + } + + async ping (peer: string | URL | PeerId | Multiaddr | Multiaddr[], options: PingHTTPOptions | PingWebSocketOptions = {}): Promise { + const start = Date.now() + const buf = new Uint8Array(PING_SIZE) + // fill buffer with random data + crypto.getRandomValues(buf) + + this.log('ping %s', peer) + const output = await raceSignal(isPingWebSocketOptions(options) ? this.webSocketPing(peer, buf, options) : this.httpPing(peer, buf, options), options?.signal ?? undefined) + const respBuf = new Uint8Array(output, 0, output.byteLength) + + if (respBuf.length !== PING_SIZE) { + throw new ProtocolError(`Unexpected response size: ${respBuf.length}`) + } + + if (!uint8ArrayEquals(respBuf, buf)) { + throw new ProtocolError('Ping body mismatch') + } + + return Date.now() - start + } + + async httpPing (peer: string | URL | PeerId | Multiaddr | Multiaddr[], buf: Uint8Array, options: PingHTTPOptions): Promise { + const res = await this.components.http.fetchProtocol(peer, HTTP_PING_PROTOCOL, { + ...options, + method: 'POST', + body: buf, + signal: options.signal ?? undefined + }) + + if (res.status !== 200) { + throw new ProtocolError(`Unexpected status code: ${res.status}`) + } + + return res.arrayBuffer() + } + + async webSocketPing (peer: string | URL | PeerId | Multiaddr | Multiaddr[], buf: Uint8Array, options: PingHTTPOptions): Promise { + const socket = await this.components.http.connectProtocol(peer, HTTP_PING_PROTOCOL, { + ...options, + signal: options.signal ?? undefined + }) + + if (socket.readyState !== WebSocket.OPEN) { + await raceEvent(socket, 'open', options.signal ?? undefined) + this.log('websocket connection to %s open', peer) + } + + const p = new Promise((resolve, reject) => { + socket.addEventListener('message', (evt) => { + this.log('received ping response from %s', peer) + resolve(evt.data) + }) + socket.addEventListener('error', (evt: any) => { + this.log('ping to %s errored - %e', peer, evt.error ?? evt) + reject(new Error('An error occurred')) + }) + socket.addEventListener('close', () => { + this.log('ping to %a closed prematurely', peer) + reject(new Error('The WebSocket was closed before the pong was received')) + }) + }) + + this.log('send ping message to %s', peer) + socket.send(buf) + + return p + } +} + +function isPingWebSocketOptions (obj: any): obj is PingWebSocketOptions { + return obj?.webSocket === true +} diff --git a/packages/http-ping/test/index.spec.ts b/packages/http-ping/test/index.spec.ts new file mode 100644 index 0000000..a1c577b --- /dev/null +++ b/packages/http-ping/test/index.spec.ts @@ -0,0 +1,5 @@ +describe('@libp2p/http-ping', () => { + it('should run a test', () => { + + }) +}) diff --git a/packages/http-ping/tsconfig.json b/packages/http-ping/tsconfig.json new file mode 100644 index 0000000..8bbbaae --- /dev/null +++ b/packages/http-ping/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ], + "references": [ + { + "path": "../http" + } + ] +} diff --git a/packages/http-ping/typedoc.json b/packages/http-ping/typedoc.json new file mode 100644 index 0000000..db0b074 --- /dev/null +++ b/packages/http-ping/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/packages/http-server/CODE_OF_CONDUCT.md b/packages/http-server/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b0fa54 --- /dev/null +++ b/packages/http-server/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/packages/http-server/LICENSE-APACHE b/packages/http-server/LICENSE-APACHE new file mode 100644 index 0000000..b09cd78 --- /dev/null +++ b/packages/http-server/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/packages/http-server/LICENSE-MIT b/packages/http-server/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/http-server/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/packages/http-server/README.md b/packages/http-server/README.md new file mode 100644 index 0000000..e8a8d7d --- /dev/null +++ b/packages/http-server/README.md @@ -0,0 +1,97 @@ +# @libp2p/http-ping + +# @libp2p/http-server + +[![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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> HTTP server components + +# About + + + +This module exports several utility functions to make creating HTTP servers +that run over HTTP quick and easy. + +## Example - Create a Node.js server + +```ts +import { createLibp2p } from 'libp2p' +import { http } from '@libp2p/http' +import { nodeServer } from '@libp2p/http-server' +import { createServer } from 'node:http' + +const server = createServer((req, res) => { + res.write('Hello world!') + res.end() +}) + +const node = await createLibp2p({ + // ...other settings + services: { + http: http({ + server: nodeServer(server) + }) + } +}) +``` + +## Example - Create a Node.js server in a browser + +The previous example can also run in a non-Node.js environment by using the +supplied `createServer` function which implements the same API as Node.js +just without depending on any Node.js internals. + +```ts +import { createServer } from '@libp2p/http-server/node' + +const server = createServer((req, res) => { + res.write('Hello world!') + res.end() +}) +``` + +# Install + +```console +$ npm i @libp2p/http-server +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-server/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-server/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/packages/http-server/package.json b/packages/http-server/package.json new file mode 100644 index 0000000..fdd6804 --- /dev/null +++ b/packages/http-server/package.json @@ -0,0 +1,184 @@ +{ + "name": "@libp2p/http-server", + "version": "0.0.0", + "description": "HTTP server components", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-server#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "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" + }, + "./node": { + "types": "./dist/src/node/index.d.ts", + "browser": "./dist/src/node/index.browser.js", + "import": "./dist/src/node/index.js" + } + }, + "release": { + "branches": [ + "main" + ], + "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": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check -i events -i readable-stream", + "release": "aegir release" + }, + "dependencies": { + "@achingbrain/http-parser-js": "^0.5.9", + "@libp2p/http": "~0.0.0", + "@libp2p/http-utils": "~0.0.0", + "@libp2p/http-websocket": "~0.0.0", + "@libp2p/interface": "^2.10.2", + "events": "^3.3.0", + "race-event": "^1.3.0", + "readable-stream": "^4.7.0", + "uint8arrays": "^5.1.0", + "ws": "^8.18.2" + }, + "devDependencies": { + "aegir": "^47.0.16" + }, + "browser": { + "./dist/src/node/index.js": "./dist/src/node/index.browser.js", + "node:events": "events", + "node:stream": "readable-stream", + "node:http": false, + "undici": false + }, + "sideEffects": false +} diff --git a/packages/http-server/src/fetch-server.ts b/packages/http-server/src/fetch-server.ts new file mode 100644 index 0000000..0b0de5e --- /dev/null +++ b/packages/http-server/src/fetch-server.ts @@ -0,0 +1,33 @@ +import { responseToStream, streamToRequest } from '@libp2p/http-utils' +import type { WebServer } from '@libp2p/http' +import type { HeaderInfo } from '@libp2p/http-utils' +import type { Stream, Connection } from '@libp2p/interface' + +export interface Fetch { + (req: Request): Promise +} + +export interface FetchServerInit { + server: Fetch +} + +class FetchServer implements WebServer { + private readonly server: Fetch + + constructor (init: FetchServerInit) { + this.server = init.server + } + + async inject (info: HeaderInfo, stream: Stream, connection: Connection): Promise { + const res = await this.server(streamToRequest(info, stream)) + await responseToStream(res, stream) + } +} + +/** + * A WebServer implementation that lets W3C Request/Response-orientated servers + * accept incoming HTTP requests opened over libp2p streams + */ +export function fetchServer (server: Fetch): WebServer { + return new FetchServer({ server }) +} diff --git a/packages/http-server/src/index.ts b/packages/http-server/src/index.ts new file mode 100644 index 0000000..bbc7fa1 --- /dev/null +++ b/packages/http-server/src/index.ts @@ -0,0 +1,47 @@ +/** + * @packageDocumentation + * + * This module exports several utility functions to make creating HTTP servers + * that run over HTTP quick and easy. + * + * @example Create a Node.js server + * + * ```ts + * import { createLibp2p } from 'libp2p' + * import { http } from '@libp2p/http' + * import { nodeServer } from '@libp2p/http-server' + * import { createServer } from 'node:http' + * + * const server = createServer((req, res) => { + * res.write('Hello world!') + * res.end() + * }) + * + * const node = await createLibp2p({ + * // ...other settings + * services: { + * http: http({ + * server: nodeServer(server) + * }) + * } + * }) + * ``` + * + * @example Create a Node.js server in a browser + * + * The previous example can also run in a non-Node.js environment by using the + * supplied `createServer` function which implements the same API as Node.js + * just without depending on any Node.js internals. + * + * ```ts + * import { createServer } from '@libp2p/http-server/node' + * + * const server = createServer((req, res) => { + * res.write('Hello world!') + * res.end() + * }) + * ``` + */ + +export { fetchServer } from './fetch-server.js' +export { nodeServer } from './node-server.js' diff --git a/packages/http-server/src/node-server.ts b/packages/http-server/src/node-server.ts new file mode 100644 index 0000000..820dcf0 --- /dev/null +++ b/packages/http-server/src/node-server.ts @@ -0,0 +1,47 @@ +import { streamToSocket } from '@libp2p/http-utils' +import type { WebServer } from '@libp2p/http' +import type { HeaderInfo } from '@libp2p/http-utils' +import type { Stream, Connection } from '@libp2p/interface' +import type { Socket } from 'node:net' + +/** + * A connection handler can emit connection events - this is all of the Node.js + * http.Server API that will be used. + */ +export interface ConnectionHandler { + emit (event: 'connection', socket: Socket): void +} + +export interface NodeServerInit { + /** + * Normally this would be an instance of `http.Server` from `node:http` + */ + server: ConnectionHandler +} + +class NodeServer implements WebServer { + private readonly server: ConnectionHandler + + constructor (init: NodeServerInit) { + this.server = init.server + } + + async inject (info: HeaderInfo, stream: Stream, connection: Connection): Promise { + // re-yield the headers to enable node to set up the request properly + const streamSource = stream.source + stream.source = (async function * () { + yield info.raw + yield * streamSource + })() + + this.server.emit('connection', streamToSocket(stream, connection)) + } +} + +/** + * A WebServer implementation that lets `node.HTTPServer` instances accept + * incoming HTTP requests opened over libp2p streams + */ +export function nodeServer (server: ConnectionHandler): WebServer { + return new NodeServer({ server }) +} diff --git a/packages/http-server/src/node/handler.ts b/packages/http-server/src/node/handler.ts new file mode 100644 index 0000000..8e5acca --- /dev/null +++ b/packages/http-server/src/node/handler.ts @@ -0,0 +1,180 @@ +import { normalizeUrl } from '@libp2p/http-utils' +import { readableToReadableStream } from '../utils.js' +import type { HTTP } from '@libp2p/http' +import type { Libp2p } from '@libp2p/interface' +import type { ServerResponse, IncomingMessage } from 'node:http' +import type { WebSocket as WSSWebSocket } from 'ws' + +export interface CanHandle { + /** + * Pass either a WebSocket instance or a IncomingMessage/ServerResponse pair + */ + (ws: WebSocket): boolean + (req: IncomingMessage, res: ServerResponse): boolean +} + +/** + * Helper function to determine whether the passed libp2p node handled the + * incoming HTTP or WebSocket request. + * + * @example Delegating handling of HTTP requests + * + * ```ts + * import { createLibp2p } from 'libp2p' + * import { canHandle } from '@libp2p/http/servers' + * import createServer from 'node:http' + * + * const libp2p = await createLibp2p({ + * // ...options + * }) + * + * const handled = canHandle(libp2p) + * + * createServer((req, res) => { + * if (handled(req, res)) { + * // libp2p handled the request, nothing else to do + * return + * } + * + * // handle request normally - pass off to express/fastify/etc or return 404 + * }) + * ``` + */ +export function canHandle (libp2p: Libp2p<{ http: HTTP }>): CanHandle { + return (...args: any[]): boolean => { + if (args.length === 1) { + const ws: WebSocket = args[0] + + if (libp2p.services.http.canHandle(ws)) { + libp2p.services.http.onWebSocket(ws) + return true + } + } else if (args.length === 2) { + const req: IncomingMessage = args[0] + const res: ServerResponse = args[1] + + if (libp2p.services.http.canHandle(req)) { + libp2p.services.http.onRequest(incomingMessageToRequest(req)) + .then(result => { + writeResponse(result, res) + }) + .catch(err => { + res.writeHead(500, err.toString()) + res.end() + }) + return true + } + } + + return false + } +} + +/** + * Adds properties/methods to a `WebSocket` instance from the `ws` module to be + * compatible with the `globalThis.WebSocket` API + */ +export function toWebSocket (ws: WSSWebSocket, req: IncomingMessage): WebSocket { + const url = normalizeUrl(req) + + Object.defineProperty(ws, 'url', { + value: url.toString(), + writable: false + }) + + // @ts-expect-error not a WS/WebSocket method + ws.dispatchEvent = (evt: Event) => { + if (evt.type === 'close') { + ws.emit('close') + } + + if (evt.type === 'open') { + ws.emit('open') + } + + if (evt.type === 'message') { + const m = evt as MessageEvent + ws.emit('data', m.data) + } + + if (evt.type === 'error') { + ws.emit('error', new Error('An error occurred')) + } + ws.emit(evt.type, evt) + } + + // @ts-expect-error ws is now WebSocket + return ws +} + +function incomingMessageToRequest (req: IncomingMessage): Request { + const headers = incomingHttpHeadersToHeaders(req.headers) + const init: RequestInit = { + method: req.method, + headers + } + + if (req.method !== 'GET' && req.method !== 'HEAD') { + // @ts-expect-error this is required by NodeJS despite being the only reasonable option https://fetch.spec.whatwg.org/#requestinit + init.duplex = 'half' + init.body = readableToReadableStream(req) + } + + const url = new URL(`http://${headers.get('host') ?? 'example.com'}${req.url ?? '/'}`) + + return new Request(url, init) +} + +function incomingHttpHeadersToHeaders (input: IncomingMessage['headers']): Headers { + const headers = new Headers() + + for (const [key, value] of Object.entries(input)) { + if (value == null) { + continue + } + + if (Array.isArray(value)) { + for (const val of value) { + headers.append(key, val) + } + } else { + headers.set(key, value) + } + } + + return headers +} + +function writeResponse (res: Response, ser: ServerResponse): void { + ser.statusCode = res.status + ser.statusMessage = res.statusText + + res.headers.forEach((val, key) => { + ser.setHeader(key, val) + }) + + if (res.body == null) { + ser.end() + } else { + const reader = res.body.getReader() + + Promise.resolve().then(async () => { + while (true) { + const { done, value } = await reader.read() + + if (value != null) { + ser.write(value) + } + + if (done) { + break + } + } + + ser.end() + }) + .catch(err => { + ser.end(err) + }) + } +} diff --git a/packages/http-server/src/node/incoming-message.ts b/packages/http-server/src/node/incoming-message.ts new file mode 100644 index 0000000..c7e52e3 --- /dev/null +++ b/packages/http-server/src/node/incoming-message.ts @@ -0,0 +1,71 @@ +import { Readable } from 'node:stream' +import { HTTPParser } from '@achingbrain/http-parser-js' +import type { HeaderInfo } from '@achingbrain/http-parser-js' +import type { IncomingHttpHeaders } from 'node:http' +import type { Socket } from 'node:net' + +export class IncomingMessage extends Readable { + public aborted: boolean + public httpVersion: string + public httpVersionMajor: number + public httpVersionMinor: number + public complete: boolean + public connection: Socket + public socket: Socket + public headers: IncomingHttpHeaders + public headersDistinct: NodeJS.Dict + public rawHeaders: string[] + public trailers: NodeJS.Dict + public trailersDistinct: NodeJS.Dict + public rawTrailers: string[] + public method?: string | undefined + public url?: string | undefined + public statusCode?: number | undefined + public statusMessage?: string | undefined + + constructor (socket: Socket, info: HeaderInfo) { + super({ + read () { + if (socket.isPaused()) { + socket.resume() + } + } + }) + this.aborted = false + this.socket = socket + this.httpVersion = `${info.versionMajor}.${info.versionMinor}` + this.httpVersionMajor = info.versionMajor + this.httpVersionMinor = info.versionMinor + this.method = HTTPParser.methods[info.method] + this.statusCode = info.statusCode + this.statusMessage = info.statusMessage + this.url = info.url + this.complete = false + this.connection = socket + this.headers = {} + this.headersDistinct = {} + this.rawHeaders = [] + this.trailers = {} + this.trailersDistinct = {} + this.rawTrailers = [] + + // set incoming headers + for (const [key, value] of info.headers.entries()) { + this.headers[key] = value + this.rawHeaders.push(key, value) + } + } + + setTimeout (msecs: number, callback?: () => void): this { + this.socket.setTimeout(msecs, callback) + return this + } + + destroy (error?: Error): this { + if (error != null) { + this.socket.destroy(error) + } + + return this + } +} diff --git a/packages/http-server/src/node/index.browser.ts b/packages/http-server/src/node/index.browser.ts new file mode 100644 index 0000000..74a141a --- /dev/null +++ b/packages/http-server/src/node/index.browser.ts @@ -0,0 +1,41 @@ +import { HTTPServer } from './server.js' +import type { ServerOptions, RequestListener, IncomingMessage, ServerResponse, Server } from 'node:http' + +export { createWebSocketServer } from './websocket-server.js' +export * from './handler.js' + +/** + * Implements the same interface as `createServer` from `node:http` just without + * any node internals. + * + * If running in a browser, instances of `http.Server` returned by this function + * could be passed to a web framework such as `express` or `fastify`, assuming + * they are runnable in browsers. + */ +export function createServer< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse> = typeof ServerResponse + > (requestListener?: RequestListener): Server +export function createServer< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse> = typeof ServerResponse + > (options: ServerOptions, + requestListener?: RequestListener): Server +export function createServer< + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse> = typeof ServerResponse +> (options: any, + requestListener?: any): Server { + if (typeof options === 'function') { + requestListener = options + options = {} + } + + const server: Server = new HTTPServer(options) + + if (requestListener != null) { + server.on('request', requestListener) + } + + return server +} diff --git a/packages/http-server/src/node/index.ts b/packages/http-server/src/node/index.ts new file mode 100644 index 0000000..b5e3b70 --- /dev/null +++ b/packages/http-server/src/node/index.ts @@ -0,0 +1,27 @@ +import type { IncomingMessage } from './incoming-message.js' +import type { ConnectionEvent } from './websocket-server.js' +import type { TypedEventTarget } from '@libp2p/interface' +import type { Duplex } from 'node:stream' + +export { createServer } from 'node:http' +export { createWebSocketServer } from './websocket-server.js' + +export interface HTTPRequestHandler { + (req: Request): Promise +} + +export interface WebSocketHandler { + (ws: WebSocket): void +} + +export interface WebSocketServerEvents { + connection: ConnectionEvent +} + +export interface WebSocketServer extends TypedEventTarget { + handleUpgrade (request: IncomingMessage, socket: Duplex, head: Uint8Array): void +} + +export type { IncomingMessage } +export type { ServerResponse } from './server-response.js' +export * from './handler.js' diff --git a/packages/http-server/src/node/server-response.ts b/packages/http-server/src/node/server-response.ts new file mode 100644 index 0000000..0cac09c --- /dev/null +++ b/packages/http-server/src/node/server-response.ts @@ -0,0 +1,252 @@ +import { Writable } from 'node:stream' +import { STATUS_CODES } from '@libp2p/http-utils' +import { InvalidParametersError } from '@libp2p/interface' +import { fromString as uint8arrayFromString } from 'uint8arrays/from-string' +import type { IncomingMessage } from './incoming-message.js' +import type { OutgoingHttpHeader, OutgoingHttpHeaders } from 'node:http' +import type { Socket } from 'node:net' + +export class ServerResponse extends Writable { + public req: Request + public chunkedEncoding: boolean + public shouldKeepAlive: boolean + public useChunkedEncodingByDefault: boolean + public sendDate: boolean + public finished: boolean + public headersSent: boolean + public connection: Socket | null + public socket: Socket | null + public statusCode: number + public statusMessage: string + public strictContentLength: boolean + + private readonly headers: Record> + private sentHeaders: boolean + + constructor (req: Request, socket: Socket) { + super() + + this.req = req + this.headers = {} + this.socket = socket + this.connection = socket + this.chunkedEncoding = false + this.shouldKeepAlive = false + this.useChunkedEncodingByDefault = false + this.sendDate = false + this.finished = false + this.headersSent = false + this.strictContentLength = false + this.sentHeaders = false + this.statusCode = 200 + this.statusMessage = STATUS_CODES[this.statusCode] + } + + _write (chunk: any, encoding: BufferEncoding, callback: (error?: Error | null) => void): void { + this.flushHeaders(() => { + this.socket?.write(chunk, encoding, callback) + }) + } + + _final (callback: (error?: Error | null) => void): void { + this.flushHeaders(() => { + this.socket?.end(callback) + }) + } + + _destroy (error: Error | null, callback: (error?: Error | null) => void): void { + this.socket?.destroy(error ?? undefined) + callback() + } + + setTimeout (msecs: number, callback?: () => void): this { + this.socket?.setTimeout(msecs, callback) + return this + } + + setHeader (name: string, value: number | string | string[]): this { + this.headers[name] = value + return this + } + + setHeaders (headers: Headers | Map): this { + for (const [key, value] of headers.entries()) { + this.setHeader(key, value) + } + + return this + } + + appendHeader (name: string, value: string | string[]): this { + if (this.headers[name] == null) { + this.headers[name] = value + } else { + let existingValue = this.headers[name] + + if (!Array.isArray(existingValue)) { + existingValue = [existingValue] + this.headers[name] = existingValue + } + + if (Array.isArray(value)) { + existingValue.push(...value) + } else { + existingValue.push(value) + } + } + + return this + } + + getHeader (name: string): number | string | string[] | undefined { + const existingValue = this.headers[name] + + if (Array.isArray(existingValue)) { + return existingValue.map(v => v.toString()) + } + + return existingValue + } + + getHeaders (): OutgoingHttpHeaders { + const output: OutgoingHttpHeaders = {} + + for (const name of Object.keys(this.headers)) { + output[name] = this.getHeader(name) + } + + return output + } + + getHeaderNames (): string[] { + return [...Object.keys(this.headers)] + } + + hasHeader (name: string): boolean { + return this.headers[name] != null + } + + removeHeader (name: string): void { + delete this.headers[name] + } + + addTrailers (headers: OutgoingHttpHeaders | ReadonlyArray<[string, string]>): void { + + } + + flushHeaders (callback?: () => void): void { + if (this.sentHeaders) { + callback?.() + return + } + + this.sentHeaders = true + + const res = [ + `HTTP/1.1 ${this.statusCode} ${this.statusMessage}`, + ...writeHeaders(this.headers), + '', + '' + ] + + this.socket?.write(uint8arrayFromString(res.join('\r\n')), callback) + } + + writeContinue (callback?: () => void): void { + const res = [ + `HTTP/1.1 100 ${STATUS_CODES[100]}`, + '', + '' + ] + + this.socket?.write(uint8arrayFromString(res.join('\r\n')), callback) + } + + writeEarlyHints (hints: Record, callback?: () => void): void { + const res = [ + `HTTP/1.1 103 ${STATUS_CODES[103]}`, + ...writeHeaders(hintsToHeaders(hints)), + '', + '' + ] + + this.socket?.write(uint8arrayFromString(res.join('\r\n')), callback) + } + + writeHead (statusCode: number, statusMessage?: string, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[]): this + writeHead (statusCode: number, headers?: OutgoingHttpHeaders | OutgoingHttpHeader[]): this + writeHead (...args: any[]): this { + const statusCode = parseInt(args[0] ?? this.statusCode, 10) + let headers: OutgoingHttpHeaders | OutgoingHttpHeader[] | undefined = args[1] + + if (args.length === 3) { + this.statusMessage = args[1] ?? this.statusMessage + headers = args[2] + } + + if (headers != null) { + for (const [key, value] of Object.keys(headers)) { + this.setHeader(key, value) + } + } + + if (STATUS_CODES[statusCode] == null) { + throw new InvalidParametersError(`Unknown status code ${statusCode}`) + } + + this.statusCode = statusCode + + this.flushHeaders() + + return this + } + + writeProcessing (): void { + const res = [ + `HTTP/1.1 102 ${STATUS_CODES[102]}`, + '', + '' + ] + + this.socket?.write(uint8arrayFromString(res.join('\r\n'))) + } + + end (cb?: (() => void) | undefined): this + end (chunk: any, cb?: (() => void) | undefined): this + end (chunk: any, encoding: BufferEncoding, cb?: (() => void) | undefined): this + end (chunk?: any, encoding?: any, cb?: any): this { + super.end(chunk, encoding, cb) + + return this + } +} + +function hintsToHeaders (hints: Record): Record { + const output: Record = {} + + for (const [key, value] of Object.entries(hints)) { + output[key] = Array.isArray(value) ? value : [value] + } + + return output +} + +function writeHeaders (headers: Record>): string[] { + const output = [] + + for (const [key, value] of Object.entries(headers)) { + if (value == null) { + continue + } + + if (Array.isArray(value)) { + value.forEach(value => { + output.push(`${key}: ${value}`) + }) + } else { + output.push(`${key}: ${value}`) + } + } + + return output +} diff --git a/packages/http-server/src/node/server.ts b/packages/http-server/src/node/server.ts new file mode 100644 index 0000000..3e9af42 --- /dev/null +++ b/packages/http-server/src/node/server.ts @@ -0,0 +1,149 @@ +import { EventEmitter } from 'node:events' +import { HTTPParser } from '@achingbrain/http-parser-js' +import { NOT_IMPLEMENTED_ERROR } from '@libp2p/http-utils' +import { IncomingMessage as IncomingMessageClass } from './incoming-message.js' +import { ServerResponse as ServerResponseClass } from './server-response.js' +import type { ServerOptions, ServerResponse, IncomingMessage } from 'node:http' +import type { AddressInfo, Socket } from 'node:net' + +export interface HTTPServerEvents { + request: [Request, Response] +} + +export class HTTPServer < + Request extends typeof IncomingMessage = typeof IncomingMessage, + Response extends typeof ServerResponse> = typeof ServerResponse +> extends EventEmitter { + public maxHeadersCount: number | null + public maxHeaderSize: number | null + public maxRequestsPerSocket: number | null + public timeout: number + public headersTimeout: number + public keepAliveTimeout: number + public requestTimeout: number + public maxConnections: number + public connections: number + private _listening: boolean + private readonly _options: ServerOptions + + constructor (options: ServerOptions = {}) { + super() + + this.maxHeadersCount = 0 + this.maxRequestsPerSocket = 0 + this.timeout = 0 + this.headersTimeout = 120_000 + this.keepAliveTimeout = options.keepAliveTimeout ?? 0 + this.requestTimeout = options.requestTimeout ?? 120_000 + this.maxHeaderSize = options.maxHeaderSize ?? HTTPParser.maxHeaderSize + this.maxConnections = 0 + this.connections = 0 + this._listening = false + this._options = options + + this.on('connection', this._handleConnection.bind(this)) + } + + private _handleConnection (socket: Socket): void { + let req: IncomingMessage | undefined + + const parser = new HTTPParser('REQUEST') + parser.maxHeaderSize = this.maxHeaderSize ?? HTTPParser.maxHeaderSize + parser[HTTPParser.kOnHeadersComplete] = (info) => { + const headers = new Headers() + + // set incoming headers + for (let i = 0; i < info.headers.length; i += 2) { + headers.append(info.headers[i].toLowerCase(), info.headers[i + 1]) + } + + req = new IncomingMessageClass(socket, { + ...info, + headers + }) + const res = new ServerResponseClass(req, socket) + + if (info.upgrade) { + const listeners = this.listenerCount('upgrade') + + if (listeners === 0) { + socket.write(NOT_IMPLEMENTED_ERROR) + // socket.end() + return + } else { + this.emit('upgrade', req, socket, new Uint8Array(0)) + return + } + } + + this.emit('request', req, res) + } + parser[HTTPParser.kOnBody] = (buf) => { + req?.push(buf) + } + + parser[HTTPParser.kOnMessageComplete] = () => { + req?.push(null) + } + + socket.on('data', (chunk) => { + parser.execute(chunk, 0, chunk.byteLength) + }) + socket.on('end', () => { + parser.finish() + req?.push(null) + }) + } + + setTimeout (...args: any[]): this { + return this + } + + closeAllConnections (): void { + + } + + closeIdleConnections (): void { + + } + + listen (...args: any[]): this { + this._listening = true + return this + } + + close (callback?: (err?: Error) => void): this { + this._listening = false + callback?.() + return this + } + + address (): AddressInfo | string | null { + return null + } + + getConnections (cb: (error: Error | null, count: number) => void): this { + cb(null, this.connections) + return this + } + + ref (): this { + return this + } + + unref (): this { + return this + } + + get listening (): boolean { + return this._listening + } + + set listening (listening: boolean) { + + } + + async [Symbol.asyncDispose] (): Promise { + + } +} diff --git a/packages/http-server/src/node/websocket-server.ts b/packages/http-server/src/node/websocket-server.ts new file mode 100644 index 0000000..bb49f0a --- /dev/null +++ b/packages/http-server/src/node/websocket-server.ts @@ -0,0 +1,82 @@ +import { INTERNAL_SERVER_ERROR } from '@libp2p/http-utils' +import { ServerWebSocket } from '@libp2p/http-websocket' +import { TypedEventEmitter } from '@libp2p/interface' +import { raceEvent } from 'race-event' +import type { IncomingMessage } from './incoming-message.js' +import type { WebSocketServerEvents, WebSocketServer as WebSocketServerInterface } from './index.js' +import type { Duplex } from 'node:stream' + +const DEFAULT_UPGRADE_TIMEOUT = 10_000 + +export interface WebSocketServerInit { + upgradeTimeout?: number +} + +class WebSocketServer extends TypedEventEmitter { + private readonly upgradeTimeout: number + + constructor (init: WebSocketServerInit = {}) { + super() + + this.upgradeTimeout = init.upgradeTimeout ?? DEFAULT_UPGRADE_TIMEOUT + } + + handleUpgrade (request: IncomingMessage, socket: Duplex, head: Uint8Array): void { + Promise.resolve() + .then(async () => { + const ws = new ServerWebSocket(request, socket) + + await raceEvent(ws, 'open', AbortSignal.timeout(this.upgradeTimeout)) + + this.dispatchEvent(new ConnectionEvent(ws, request)) + }) + .catch(() => { + socket.write(INTERNAL_SERVER_ERROR) + }) + } +} + +export class ConnectionEvent extends Event { + webSocket: WebSocket + request: IncomingMessage + + constructor (ws: WebSocket, req: IncomingMessage) { + super('connection') + + this.webSocket = ws + this.request = req + } +} + +/** + * Creates a WebSocket server that can handle upgrade requests from clients. + * + * Add a listener for the `connection` event to receive incoming WebSocket + * connections. + * + * @example + * + * ```ts + * import { createServer, createWebSocketServer } from '@libp2p/http' + * + * const wss = createWebSocketServer() + * wss.addEventListener('connection', (evt) => { + * const ws = evt.webSocket + * + * ws.addEventListener('message', (evt) => { + * ws.send(evt.data) + * }) + * }) + * + * const server = createServer((req, res) => { + * // handle HTTP request + * }) + * + * server.addListener('upgrade', (request, socket, head) => { + * wss.handleUpgrade(request, socket, head) + * }) + * `` + */ +export function createWebSocketServer (): WebSocketServerInterface { + return new WebSocketServer() +} diff --git a/packages/http-server/src/utils.ts b/packages/http-server/src/utils.ts new file mode 100644 index 0000000..c9f0361 --- /dev/null +++ b/packages/http-server/src/utils.ts @@ -0,0 +1,24 @@ +import type { Readable } from 'node:stream' + +export function readableToReadableStream (readable: Readable): ReadableStream { + return new ReadableStream({ + start (controller) { + readable.on('data', buf => { + controller.enqueue(buf) + + // pause until more data requested (backpressure) + readable.pause() + }) + readable.on('end', () => { + controller.close() + }) + readable.on('error', (err) => { + controller.error(err) + }) + }, + pull () { + // let data flow again + readable.resume() + } + }) +} diff --git a/packages/http-server/test/index.spec.ts b/packages/http-server/test/index.spec.ts new file mode 100644 index 0000000..9eb526c --- /dev/null +++ b/packages/http-server/test/index.spec.ts @@ -0,0 +1,5 @@ +describe('@libp2p/http-server', () => { + it('should run a test', () => { + + }) +}) diff --git a/packages/http-server/tsconfig.json b/packages/http-server/tsconfig.json new file mode 100644 index 0000000..8cd6cfb --- /dev/null +++ b/packages/http-server/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ], + "references": [ + { + "path": "../http" + }, + { + "path": "../http-utils" + }, + { + "path": "../http-websocket" + } + ] +} diff --git a/packages/http-server/typedoc.json b/packages/http-server/typedoc.json new file mode 100644 index 0000000..939d9c7 --- /dev/null +++ b/packages/http-server/typedoc.json @@ -0,0 +1,7 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts", + "./src/node/index.ts" + ] +} diff --git a/packages/http-utils/CODE_OF_CONDUCT.md b/packages/http-utils/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b0fa54 --- /dev/null +++ b/packages/http-utils/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/packages/http-utils/LICENSE-APACHE b/packages/http-utils/LICENSE-APACHE new file mode 100644 index 0000000..b09cd78 --- /dev/null +++ b/packages/http-utils/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/packages/http-utils/LICENSE-MIT b/packages/http-utils/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/http-utils/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/packages/http-utils/README.md b/packages/http-utils/README.md new file mode 100644 index 0000000..27e6771 --- /dev/null +++ b/packages/http-utils/README.md @@ -0,0 +1,56 @@ +# @libp2p/http-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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> Shared utils and common code for HTTP modules + +# About + + + +Contains shared code and utilities used by `@libp2p/http-*` modules. + +# Install + +```console +$ npm i @libp2p/http-utils +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-utils/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-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/packages/http-utils/package.json b/packages/http-utils/package.json new file mode 100644 index 0000000..226fb9e --- /dev/null +++ b/packages/http-utils/package.json @@ -0,0 +1,162 @@ +{ + "name": "@libp2p/http-utils", + "version": "0.0.0", + "description": "Shared utils and common code for HTTP modules", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-utils#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/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" + } + }, + "release": { + "branches": [ + "main" + ], + "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": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check -i readable-stream", + "release": "aegir release" + }, + "dependencies": { + "@achingbrain/http-parser-js": "^0.5.9", + "@libp2p/interface": "^2.10.2", + "@libp2p/peer-id": "^5.1.5", + "@multiformats/multiaddr": "^12.4.0", + "@multiformats/multiaddr-to-uri": "^11.0.0", + "@multiformats/uri-to-multiaddr": "^9.0.1", + "it-byte-stream": "^2.0.2", + "it-queueless-pushable": "^2.0.1", + "it-to-browser-readablestream": "^2.0.11", + "multiformats": "^13.3.6", + "readable-stream": "^4.7.0", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + }, + "devDependencies": { + "aegir": "^47.0.16" + }, + "browser": { + "node:stream": "readable-stream" + }, + "sideEffects": false +} diff --git a/packages/http-utils/src/constants.ts b/packages/http-utils/src/constants.ts new file mode 100644 index 0000000..72bb937 --- /dev/null +++ b/packages/http-utils/src/constants.ts @@ -0,0 +1,77 @@ +export const HTTP_PATH_CODEC = 0x01e1 +export const HTTP_CODEC = 0x01e0 +export const DNS_CODEC = 0x35 +export const DNS4_CODEC = 0x36 +export const DNS6_CODEC = 0x37 +export const DNSADDR_CODEC = 0x38 +export const DNS_CODECS = [ + DNS_CODEC, + DNS4_CODEC, + DNS6_CODEC, + DNSADDR_CODEC +] +export const STATUS_CODES: Record = { + 100: 'Continue', // RFC 7231 6.2.1 + 101: 'Switching Protocols', // RFC 7231 6.2.2 + 102: 'Processing', // RFC 2518 10.1 (obsoleted by RFC 4918) + 103: 'Early Hints', // RFC 8297 2 + 200: 'OK', // RFC 7231 6.3.1 + 201: 'Created', // RFC 7231 6.3.2 + 202: 'Accepted', // RFC 7231 6.3.3 + 203: 'Non-Authoritative Information', // RFC 7231 6.3.4 + 204: 'No Content', // RFC 7231 6.3.5 + 205: 'Reset Content', // RFC 7231 6.3.6 + 206: 'Partial Content', // RFC 7233 4.1 + 207: 'Multi-Status', // RFC 4918 11.1 + 208: 'Already Reported', // RFC 5842 7.1 + 226: 'IM Used', // RFC 3229 10.4.1 + 300: 'Multiple Choices', // RFC 7231 6.4.1 + 301: 'Moved Permanently', // RFC 7231 6.4.2 + 302: 'Found', // RFC 7231 6.4.3 + 303: 'See Other', // RFC 7231 6.4.4 + 304: 'Not Modified', // RFC 7232 4.1 + 305: 'Use Proxy', // RFC 7231 6.4.5 + 307: 'Temporary Redirect', // RFC 7231 6.4.7 + 308: 'Permanent Redirect', // RFC 7238 3 + 400: 'Bad Request', // RFC 7231 6.5.1 + 401: 'Unauthorized', // RFC 7235 3.1 + 402: 'Payment Required', // RFC 7231 6.5.2 + 403: 'Forbidden', // RFC 7231 6.5.3 + 404: 'Not Found', // RFC 7231 6.5.4 + 405: 'Method Not Allowed', // RFC 7231 6.5.5 + 406: 'Not Acceptable', // RFC 7231 6.5.6 + 407: 'Proxy Authentication Required', // RFC 7235 3.2 + 408: 'Request Timeout', // RFC 7231 6.5.7 + 409: 'Conflict', // RFC 7231 6.5.8 + 410: 'Gone', // RFC 7231 6.5.9 + 411: 'Length Required', // RFC 7231 6.5.10 + 412: 'Precondition Failed', // RFC 7232 4.2 + 413: 'Payload Too Large', // RFC 7231 6.5.11 + 414: 'URI Too Long', // RFC 7231 6.5.12 + 415: 'Unsupported Media Type', // RFC 7231 6.5.13 + 416: 'Range Not Satisfiable', // RFC 7233 4.4 + 417: 'Expectation Failed', // RFC 7231 6.5.14 + 418: 'I\'m a Teapot', // RFC 7168 2.3.3 + 421: 'Misdirected Request', // RFC 7540 9.1.2 + 422: 'Unprocessable Entity', // RFC 4918 11.2 + 423: 'Locked', // RFC 4918 11.3 + 424: 'Failed Dependency', // RFC 4918 11.4 + 425: 'Too Early', // RFC 8470 5.2 + 426: 'Upgrade Required', // RFC 2817 and RFC 7231 6.5.15 + 428: 'Precondition Required', // RFC 6585 3 + 429: 'Too Many Requests', // RFC 6585 4 + 431: 'Request Header Fields Too Large', // RFC 6585 5 + 451: 'Unavailable For Legal Reasons', // RFC 7725 3 + 500: 'Internal Server Error', // RFC 7231 6.6.1 + 501: 'Not Implemented', // RFC 7231 6.6.2 + 502: 'Bad Gateway', // RFC 7231 6.6.3 + 503: 'Service Unavailable', // RFC 7231 6.6.4 + 504: 'Gateway Timeout', // RFC 7231 6.6.5 + 505: 'HTTP Version Not Supported', // RFC 7231 6.6.6 + 506: 'Variant Also Negotiates', // RFC 2295 8.1 + 507: 'Insufficient Storage', // RFC 4918 11.5 + 508: 'Loop Detected', // RFC 5842 7.2 + 509: 'Bandwidth Limit Exceeded', + 510: 'Not Extended', // RFC 2774 7 + 511: 'Network Authentication Required' // RFC 6585 6 +} diff --git a/packages/http-utils/src/index.ts b/packages/http-utils/src/index.ts new file mode 100644 index 0000000..e3be58c --- /dev/null +++ b/packages/http-utils/src/index.ts @@ -0,0 +1,561 @@ +/** + * @packageDocumentation + * + * Contains shared code and utilities used by `@libp2p/http-*` modules. + */ + +import { HTTPParser } from '@achingbrain/http-parser-js' +import { InvalidParametersError, isPeerId, ProtocolError } from '@libp2p/interface' +import { peerIdFromString } from '@libp2p/peer-id' +import { fromStringTuples, isMultiaddr, multiaddr } from '@multiformats/multiaddr' +import { multiaddrToUri } from '@multiformats/multiaddr-to-uri' +import { uriToMultiaddr } from '@multiformats/uri-to-multiaddr' +import { queuelessPushable } from 'it-queueless-pushable' +import itToBrowserReadableStream from 'it-to-browser-readablestream' +import { base36 } from 'multiformats/bases/base36' +import { base64pad } from 'multiformats/bases/base64' +import { sha1 } from 'multiformats/hashes/sha1' +import { Uint8ArrayList } from 'uint8arraylist' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { DNS_CODECS, HTTP_CODEC, HTTP_PATH_CODEC } from './constants.js' +import { Request } from './request.js' +import type { AbortOptions, PeerId, Stream } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +/** + * A subset of options passed to middleware + */ +export interface MiddlewareOptions extends AbortOptions { + method: string + headers: Headers + middleware: Middleware[] + credentials?: RequestCredentials + keepalive?: boolean + redirect?: RequestRedirect + integrity?: string + mode?: RequestMode + referrer?: string + referrerPolicy?: ReferrerPolicy +} + +/** + * Middleware that allows augmenting the client request/response with additional + * fields or headers. + */ +export interface Middleware { + /** + * Called before a request is made + */ + prepareRequest?(resource: URL | Multiaddr[], opts: MiddlewareOptions): void | Promise + + /** + * Called after a request is made but before the body has been read - the + * processor may do any necessary housekeeping based on the server response + */ + processResponse?(resource: URL | Multiaddr[], opts: MiddlewareOptions, response: Response): void | Promise +} + +export function toURL (resource: URL | Multiaddr[], headers: Headers): URL { + if (resource instanceof URL) { + return resource + } + + const host = getHost(resource, headers) + const { httpPath } = stripHTTPPath(resource) + + return new URL(`http://${host}${httpPath}`) +} + +/** + * Normalizes byte-like input to a `Uint8Array` + */ +export function toUint8Array (obj: DataView | ArrayBuffer | Uint8Array): Uint8Array { + if (obj instanceof Uint8Array) { + return obj + } + + if (obj instanceof DataView) { + return new Uint8Array(obj.buffer, obj.byteOffset, obj.byteLength) + } + + return new Uint8Array(obj, 0, obj.byteLength) +} + +export function streamToRequest (info: HeaderInfo, stream: Stream): globalThis.Request { + const init: RequestInit = { + method: info.method, + headers: info.headers + } + + if ((init.method !== 'GET' || info.upgrade) && init.method !== 'HEAD') { + let source: AsyncGenerator = stream.source + + if (!info.upgrade) { + source = takeBytes(stream.source, info.headers.get('content-length')) + } + + init.body = itToBrowserReadableStream(source) + // @ts-expect-error this is required by NodeJS despite being the only reasonable option https://fetch.spec.whatwg.org/#requestinit + init.duplex = 'half' + } + + return new Request(normalizeUrl(info).toString(), init) +} + +export async function responseToStream (res: Response, stream: Stream): Promise { + const pushable = queuelessPushable() + stream.sink(pushable) + .catch(err => { + stream.abort(err) + }) + + await pushable.push(uint8ArrayFromString([ + `HTTP/1.1 ${res.status} ${res.statusText}`, + ...writeHeaders(res.headers), + '', + '' + ].join('\r\n'))) + + if (res.body == null) { + await pushable.end() + return + } + + const reader = res.body.getReader() + let result = await reader.read() + + while (true) { + if (result.value != null) { + await pushable.push(result.value) + } + + if (result.done) { + break + } + + result = await reader.read() + } + + await pushable.end() + + await stream.closeWrite() + .catch(err => { + stream.abort(err) + }) +} + +export const NOT_FOUND_RESPONSE = uint8ArrayFromString([ + 'HTTP/1.1 404 Not Found', + 'Connection: close', + '', + '' +].join('\r\n')) + +export const BAD_REQUEST = uint8ArrayFromString([ + 'HTTP/1.1 400 Bad Request', + 'Connection: close', + '', + '' +].join('\r\n')) + +export const INTERNAL_SERVER_ERROR = uint8ArrayFromString([ + 'HTTP/1.1 500 Internal Server Error', + 'Connection: close', + '', + '' +].join('\r\n')) + +export const NOT_IMPLEMENTED_ERROR = uint8ArrayFromString([ + 'HTTP/1.1 501 Not Implemented', + 'Connection: close', + '', + '' +].join('\r\n')) + +export function writeHeaders (headers: Headers): string[] { + const output = [] + + if (headers.get('Connection') == null) { + headers.set('Connection', 'close') + } + + for (const [key, value] of headers.entries()) { + output.push(`${key}: ${value}`) + } + + return output +} + +async function * takeBytes (source: AsyncGenerator, bytes?: number | string | null): AsyncGenerator { + bytes = parseInt(`${bytes ?? ''}`) + + if (bytes == null || isNaN(bytes)) { + return source + } + + let count = 0 + + for await (const buf of source) { + count += buf.byteLength + + if (count > bytes) { + yield buf.subarray(0, count - bytes) + return + } + + yield buf.subarray() + + if (count === bytes) { + return + } + } +} + +/** + * Attempts to convert the passed `resource` into a HTTP(s) URL or an array of + * multiaddrs. + * + * The returned URL should be handled by the global fetch, the multiaddr(s) + * should be handled by libp2p. + */ +export function toResource (resource: string | URL | PeerId | Multiaddr | Multiaddr[], path?: string): URL | Multiaddr[] { + if (typeof resource === 'string') { + if (resource.startsWith('/')) { + resource = multiaddr(resource) + } else { + resource = new URL(resource) + } + } + + if (isPeerId(resource)) { + resource = multiaddr(`/p2p/${resource}`) + } + + if (resource instanceof URL) { + if (resource.protocol === 'multiaddr:') { + resource = uriToMultiaddr(resource.toString()) + } + } + + if (isMultiaddr(resource)) { + resource = [resource] + } + + // check for `/http/` tuple and transform to URL if present + if (Array.isArray(resource)) { + for (const ma of resource) { + const stringTuples = ma.stringTuples() + + if (stringTuples.find(([codec]) => codec === HTTP_CODEC) != null) { + const uri = multiaddrToUri(ma) + return new URL(`${uri}${path ?? ''}`) + } + } + } + + if (path == null) { + return resource + } + + if (resource instanceof URL) { + return new URL(`${resource}${path.substring(1)}`) + } + + return resource.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent(path.substring(1))}`)) +} + +export function getHeaders (init: RequestInit = {}): Headers { + if (init.headers instanceof Headers) { + return init.headers + } + + init.headers = new Headers(init.headers) + + return init.headers +} + +export function getHeader (header: string, headers: HeadersInit = {}): string | undefined { + if (headers instanceof Headers) { + return headers.get(header) ?? undefined + } + + if (Array.isArray(headers)) { + return headers.find(([key, value]) => { + if (key === header) { + return value + } + + return undefined + })?.[1] + } + + return headers[header] +} + +function isValidHost (host?: string): host is string { + return host != null && host !== '' +} + +// eslint-disable-next-line complexity +export function getHost (addresses: URL | Multiaddr[], headers: Headers): string { + let host: string | undefined + let port = 80 + let protocol = 'http:' + + if (addresses instanceof URL) { + host = addresses.hostname + port = parseInt(addresses.port, 10) + protocol = addresses.protocol + } + + if (!isValidHost(host)) { + host = headers.get('host') ?? undefined + } + + // try to extract domain from DNS addresses + if (!isValidHost(host) && Array.isArray(addresses)) { + for (const address of addresses) { + const stringTuples = address.stringTuples() + const filtered = stringTuples.filter(([key]) => DNS_CODECS.includes(key))?.[0]?.[1] + + if (filtered != null) { + host = filtered + break + } + } + } + + // try to use remote PeerId as domain + if (!isValidHost(host) && Array.isArray(addresses)) { + for (const address of addresses) { + const peerStr = address.getPeerId() + + // try to extract port from multiaddr if it is available + try { + const options = address.toOptions() + port = options.port + } catch {} + + if (peerStr != null) { + const peerId = peerIdFromString(peerStr) + // host has to be case-insensitive + host = peerId.toCID().toString(base36) + break + } + } + } + + // try use network host as domain + if (!isValidHost(host) && Array.isArray(addresses)) { + for (const address of addresses) { + try { + const options = address.toOptions() + + host = options.host + break + } catch {} + } + } + + if (isValidHost(host)) { + // add port if not standard + if (protocol === 'http:' && port !== 80) { + host = `${host}:${port}` + } + + if (protocol === 'https:' && port !== 443) { + host = `${host}:${port}` + } + + return host + } + + throw new InvalidParametersError('Could not determine request host name - a request must have a host header, be made to a DNS or IP-based multiaddr or an http(s) URL') +} + +export function stripHTTPPath (addresses: Multiaddr[]): { httpPath: string, addresses: Multiaddr[] } { + // strip http-path tuple but record the value if set + let httpPath = '/' + addresses = addresses.map(ma => { + return fromStringTuples( + ma.stringTuples().filter(t => { + if (t[0] === HTTP_PATH_CODEC && t[1] != null) { + httpPath = `/${t[1]}` + } + + return t[0] !== HTTP_PATH_CODEC + }) + ) + }) + + return { + httpPath, + addresses + } +} + +export function normalizeMethod (method?: string | string[], defaultMethod = ['GET']): string[] { + if (method == null) { + return defaultMethod + } + + if (typeof method === 'string') { + method = [method] + } + + return method.map(m => m.toUpperCase()) +} + +/** + * Returns a fully qualified URL representing the resource that is being + * requested + */ +export function normalizeUrl (req: { url?: string, headers?: Headers | { host?: string } }): URL { + const url = req.url ?? '/' + + if (url.startsWith('http')) { + return new URL(url) + } + + const host = getHostFromReq(req) + + return new URL(`http://${host}${url}`) +} + +function getHostFromReq (req: any): string { + let host = req.headers?.host + + if (host == null) { + host = req.headers?.Host + } + + if (host == null && typeof req.headers.get === 'function') { + host = req.headers.get('host') + } + + if (host == null) { + throw new InvalidParametersError('Could not read host') + } + + return host +} + +export function isWebSocketUpgrade (method: string, headers: Headers): boolean { + return method === 'GET' && headers.get('connection')?.toLowerCase() === 'upgrade' && headers.get('upgrade')?.toLowerCase() === 'websocket' +} + +/** + * Handles node.js-style headers for which the values can be string[] + */ +function getHeaderFromHeaders (headers: Headers | Record, key: string): string | undefined { + if (headers instanceof Headers) { + return headers.get(key) ?? undefined + } + + const header = headers[key] + + if (Array.isArray(header)) { + return header.join(',') + } + + return header +} + +export async function getServerUpgradeHeaders (headers: Headers | Record): Promise { + if (getHeaderFromHeaders(headers, 'sec-websocket-version') !== '13') { + throw new ProtocolError('Invalid version') + } + + const secWebSocketKey = getHeaderFromHeaders(headers, 'sec-websocket-key') + + if (secWebSocketKey == null) { + throw new ProtocolError('Missing sec-websocket-key') + } + + const token = `${secWebSocketKey}258EAFA5-E914-47DA-95CA-C5AB0DC85B11` + const hash = await sha1.digest(uint8ArrayFromString(token)) + const webSocketAccept = base64pad.encode( + hash.digest + ).substring(1) + + return new Headers({ + Upgrade: 'websocket', + Connection: 'upgrade', + 'Sec-WebSocket-Accept': webSocketAccept + }) +} + +/** + * Reads HTTP headers from an incoming stream + */ +export async function readHeaders (stream: Stream): Promise { + return new Promise((resolve, reject) => { + const parser = new HTTPParser('REQUEST') + const source = queuelessPushable() + const earlyData = new Uint8ArrayList() + let headersComplete = false + + parser[HTTPParser.kOnHeadersComplete] = (info) => { + headersComplete = true + const headers = new Headers() + + // set incoming headers + for (let i = 0; i < info.headers.length; i += 2) { + headers.set(info.headers[i].toLowerCase(), info.headers[i + 1]) + } + + resolve({ + ...info, + headers, + raw: earlyData, + method: HTTPParser.methods[info.method] + }) + } + + // replace source with request body + const streamSource = stream.source + stream.source = source + + Promise.resolve().then(async () => { + for await (const chunk of streamSource) { + // only use the message parser until the headers have been read + if (!headersComplete) { + earlyData.append(chunk) + parser.execute(chunk.subarray()) + } else { + await source.push(new Uint8ArrayList(chunk)) + } + } + + await source.end() + }) + .catch((err: Error) => { + stream.abort(err) + reject(err) + }) + .finally(() => { + parser.finish() + }) + }) +} + +/** + * Parsed from the incoming HTTP message + */ +export interface HeaderInfo { + versionMajor: number + versionMinor: number + headers: Headers + method: string + url: string + statusCode: number + statusMessage: string + upgrade: boolean + shouldKeepAlive: boolean + raw: Uint8ArrayList +} + +export * from './request.js' +export * from './response.js' +export * from './constants.js' +export * from './stream-to-socket.js' diff --git a/packages/http-utils/src/request.ts b/packages/http-utils/src/request.ts new file mode 100644 index 0000000..c3a880b --- /dev/null +++ b/packages/http-utils/src/request.ts @@ -0,0 +1,44 @@ +import { getHeaders, isWebSocketUpgrade } from './index.js' + +/** + * Extends the native Request class to be more flexible. + * + * - body - normally GET requests cannot have a body, but if the request is for + * a WebSocket upgrade, we need the body to turn into the socket + * + * Also firefox Web Workers remove the request body though weirdly the main + * thread doesn't. + * + * - headers - the global browser request removes certain headers like + * Authorization and Sec-WebSocket-Protocol but we need to preserve them + */ +export class Request extends globalThis.Request { + constructor (input: RequestInfo | URL, init: RequestInit = {}) { + const method = init.method ?? 'GET' + const headers = getHeaders(init) + const body = init.body + + if (isWebSocketUpgrade(method, headers)) { + // temporarily override the method name since undici does not allow GET + // requests with bodies + init.method = 'UPGRADE' + } + + super(input, init) + + Object.defineProperties(this, { + body: { + value: body, + writable: false + }, + method: { + value: method, + writable: false + }, + headers: { + value: headers, + writable: false + } + }) + } +} diff --git a/packages/http-utils/src/response.ts b/packages/http-utils/src/response.ts new file mode 100644 index 0000000..0c58d66 --- /dev/null +++ b/packages/http-utils/src/response.ts @@ -0,0 +1,40 @@ +import { STATUS_CODES } from './constants.js' +import { getHeaders } from './index.js' + +/** + * Extends the native Response class to be more flexible. + * + * - response headers - the fetch spec restricts access to certain headers that + * we need access to `set-cookie`, `Access-Control-*`, etc, and the native + * Response implementations remove them + * + * - status codes - we need to represent all possible HTTP status codes, not + * just those allowed by the fetch spec + */ +export class Response extends globalThis.Response { + constructor (body: BodyInit | null, init: ResponseInit = {}) { + const headers = getHeaders(init) + const status = init.status ?? 200 + + if (status < 200 || status > 599) { + init.status = 200 + } + + super(body, init) + + Object.defineProperties(this, { + status: { + value: status, + writable: false + }, + statusText: { + value: STATUS_CODES[status], + writable: false + }, + headers: { + value: headers, + writable: false + } + }) + } +} diff --git a/packages/http-utils/src/stream-to-socket.ts b/packages/http-utils/src/stream-to-socket.ts new file mode 100644 index 0000000..972fa9f --- /dev/null +++ b/packages/http-utils/src/stream-to-socket.ts @@ -0,0 +1,200 @@ +import { Duplex } from 'node:stream' +import { byteStream } from 'it-byte-stream' +import type { Connection, Stream } from '@libp2p/interface' +import type { Socket, SocketConnectOpts, AddressInfo, SocketReadyState } from 'node:net' + +const MAX_TIMEOUT = 2_147_483_647 + +class Libp2pSocket extends Duplex { + public readonly autoSelectFamilyAttemptedAddresses = [] + public readonly connecting = false + public readonly pending = false + public readonly remoteAddress: string + public bytesRead: number + public bytesWritten: number + public timeout = MAX_TIMEOUT + public allowHalfOpen: boolean + + private readonly stream: Stream + + constructor (stream: Stream, connection: Connection) { + const bytes = byteStream(stream) + + super({ + write: (chunk, encoding, cb) => { + this.stream.log('write %d bytes', chunk.byteLength) + + this.bytesWritten += chunk.byteLength + bytes.write(chunk) + .then(() => { + cb() + }, err => { + cb(err) + }) + }, + read: (size) => { + this.stream.log('asked to read %d bytes', size) + + void Promise.resolve().then(async () => { + try { + while (true) { + const chunk = await bytes.read({ + signal: AbortSignal.timeout(this.timeout) + }) + + if (chunk == null) { + this.stream.log('socket readable end closed') + this.push(null) + return + } + + this.bytesRead += chunk.byteLength + + this.stream.log('socket read %d bytes', chunk.byteLength) + const more = this.push(chunk.subarray()) + + if (!more) { + break + } + } + } catch (err: any) { + this.destroy(err) + } + }) + }, + destroy: (err, cb) => { + this.stream.log('destroy with %d bytes buffered - %e', this.bufferSize, err) + + if (err != null) { + bytes.unwrap().abort(err) + cb() + } else { + bytes.unwrap().close() + .then(() => { + cb() + }) + .catch(err => { + stream.abort(err) + cb(err) + }) + } + }, + final: (cb) => { + this.stream.log('final') + + bytes.unwrap().closeWrite() + .then(() => { + cb() + }) + .catch(err => { + bytes.unwrap().abort(err) + cb(err) + }) + } + }) + + this.stream = stream + this.remoteAddress = connection.remoteAddr.toString() + this.bytesRead = 0 + this.bytesWritten = 0 + this.allowHalfOpen = true + } + + public get readyState (): SocketReadyState { + if (this.stream.status === 'closed') { + return 'closed' + } + + if (this.stream.writeStatus === 'closed' || this.stream.writeStatus === 'closing') { + return 'readOnly' + } + + if (this.stream.readStatus === 'closed' || this.stream.readStatus === 'closing') { + return 'writeOnly' + } + + return 'open' + } + + public get bufferSize (): number { + return this.writableLength + } + + destroySoon (): void { + this.stream.log('destroySoon with %d bytes buffered', this.bufferSize) + this.destroy() + } + + connect (options: SocketConnectOpts, connectionListener?: () => void): this + connect (port: number, host: string, connectionListener?: () => void): this + connect (port: number, connectionListener?: () => void): this + connect (path: string, connectionListener?: () => void): this + connect (...args: any[]): this { + this.stream.log('connect %o', args) + return this + } + + setEncoding (encoding?: BufferEncoding): this { + this.stream.log('setEncoding %s', encoding) + return this + } + + resetAndDestroy (): this { + this.stream.log('resetAndDestroy') + this.stream.abort(new Error('Libp2pSocket.resetAndDestroy')) + + return this + } + + setTimeout (timeout: number, callback?: () => void): this { + this.stream.log('setTimeout %d', timeout) + + if (callback != null) { + this.addListener('timeout', callback) + } + + this.timeout = timeout === 0 ? MAX_TIMEOUT : timeout + + return this + } + + setNoDelay (noDelay?: boolean): this { + this.stream.log('setNoDelay %b', noDelay) + + return this + } + + setKeepAlive (enable?: boolean, initialDelay?: number): this { + this.stream.log('setKeepAlive %b %d', enable, initialDelay) + + return this + } + + address (): AddressInfo | Record { + this.stream.log('address') + + return {} + } + + unref (): this { + this.stream.log('unref') + + return this + } + + ref (): this { + this.stream.log('ref') + + return this + } + + write (buffer: Uint8Array | string, cb?: (err?: Error) => void): boolean + write (str: Uint8Array | string, encoding?: BufferEncoding, cb?: (err?: Error) => void): boolean + write (chunk: any, encoding?: any, cb?: any): boolean { + return super.write(chunk, encoding, cb) + } +} + +export function streamToSocket (stream: Stream, connection: Connection): Socket { + return new Libp2pSocket(stream, connection) +} diff --git a/packages/http-utils/test/index.spec.ts b/packages/http-utils/test/index.spec.ts new file mode 100644 index 0000000..8ef9719 --- /dev/null +++ b/packages/http-utils/test/index.spec.ts @@ -0,0 +1,5 @@ +describe('@libp2p/http-utils', () => { + it('should run a test', () => { + + }) +}) diff --git a/packages/http-utils/tsconfig.json b/packages/http-utils/tsconfig.json new file mode 100644 index 0000000..13a3599 --- /dev/null +++ b/packages/http-utils/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ] +} diff --git a/packages/http-utils/typedoc.json b/packages/http-utils/typedoc.json new file mode 100644 index 0000000..db0b074 --- /dev/null +++ b/packages/http-utils/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/packages/http-websocket/CODE_OF_CONDUCT.md b/packages/http-websocket/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b0fa54 --- /dev/null +++ b/packages/http-websocket/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/packages/http-websocket/LICENSE-APACHE b/packages/http-websocket/LICENSE-APACHE new file mode 100644 index 0000000..b09cd78 --- /dev/null +++ b/packages/http-websocket/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/packages/http-websocket/LICENSE-MIT b/packages/http-websocket/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/http-websocket/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/packages/http-websocket/README.md b/packages/http-websocket/README.md new file mode 100644 index 0000000..9e30bae --- /dev/null +++ b/packages/http-websocket/README.md @@ -0,0 +1,60 @@ +# @libp2p/http-client + +# @libp2p/http-websocket + +[![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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> libp2p-compatible implementation of the WebSocket API + +# About + + + +This is an implementation of the [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) +that uses libp2p streams as the underlying transport layer, instead of a TCP +socket. + +# Install + +```console +$ npm i @libp2p/http-websocket +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-websocket/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http-websocket/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/packages/http-websocket/package.json b/packages/http-websocket/package.json new file mode 100644 index 0000000..85a9df1 --- /dev/null +++ b/packages/http-websocket/package.json @@ -0,0 +1,162 @@ +{ + "name": "@libp2p/http-websocket", + "version": "0.0.0", + "description": "libp2p-compatible implementation of the WebSocket API", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/http-websocket#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/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" + } + }, + "release": { + "branches": [ + "main" + ], + "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": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check", + "release": "aegir release" + }, + "dependencies": { + "@achingbrain/http-parser-js": "^0.5.9", + "@libp2p/http-utils": "~0.0.0", + "@libp2p/interface": "^2.10.2", + "@libp2p/interface-internal": "^2.3.14", + "@libp2p/utils": "^6.6.5", + "@multiformats/multiaddr": "^12.4.0", + "it-byte-stream": "^2.0.2", + "multiformats": "^13.3.6", + "uint8arraylist": "^2.4.8", + "uint8arrays": "^5.1.0" + }, + "devDependencies": { + "aegir": "^47.0.16" + }, + "browser": { + "./dist/src/auth/agent.js": "./dist/src/auth/agent.browser.js", + "./dist/src/http.js": "./dist/src/http.browser.js", + "./dist/src/http/index.js": "./dist/src/http/index.browser.js", + "./dist/test/index.spec.js": "./dist/test/index.browser.spec.js" + }, + "sideEffects": false +} diff --git a/packages/http-websocket/src/events.ts b/packages/http-websocket/src/events.ts new file mode 100644 index 0000000..d317689 --- /dev/null +++ b/packages/http-websocket/src/events.ts @@ -0,0 +1,35 @@ +export class ErrorEvent extends Event { + public readonly message: string + public readonly error: Error + public readonly filename = '' + public readonly lineno = 0 + public readonly colno = 0 + + constructor (err: Error) { + super('error') + this.error = err + this.message = err.message + } +} + +export interface CloseEventInit extends EventInit { + code?: number + reason?: string + wasClean?: boolean +} + +/** + * Can remove once node.js 24 becomes LTS + */ +export class CloseEvent extends Event { + public readonly code: number + public readonly reason: string + public readonly wasClean: boolean + + constructor (type: string, eventInitDict?: CloseEventInit) { + super(type) + this.code = eventInitDict?.code ?? 0 + this.reason = eventInitDict?.reason ?? '' + this.wasClean = eventInitDict?.wasClean ?? true + } +} diff --git a/packages/http-websocket/src/index.ts b/packages/http-websocket/src/index.ts new file mode 100644 index 0000000..c7f9180 --- /dev/null +++ b/packages/http-websocket/src/index.ts @@ -0,0 +1,62 @@ +/** + * @packageDocumentation + * + * This is an implementation of the [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) + * that uses libp2p streams as the underlying transport layer, instead of a TCP + * socket. + */ + +import type { AbortOptions } from '@libp2p/interface' + +export interface WebSocketEvents { + close: CloseEvent + error: Event + message: MessageEvent + open: Event +} + +export interface CloseListener { + (evt: CloseEvent): void +} + +export interface ErrorListener { + (evt: Event): void +} + +export interface MessageListener { + (evt: MessageEvent): void +} + +export interface OpenListener { + (evt: Event): void +} +/* +export interface WebSocket extends TypedEventTarget { + CONNECTING: 0 + OPEN: 1 + CLOSING: 2 + CLOSED: 3 + binaryType: BinaryType + bufferedAmount: number + extensions: string + protocol: string + readyState: number + url: string + onopen: OpenListener | null + onmessage: MessageListener | null + onerror: ErrorListener | null + onclose: CloseListener | null + + close (code?: number, reason?: string): void + send (data: string | Blob | Uint8Array | ArrayBuffer | DataView): void +} + */ + +export interface WebSocketInit extends AbortOptions { + headers: Headers + protocols?: string[] + onHandshakeResponse?(res: Response): Promise +} + +export { WebSocket, RequestWebSocket, StreamWebSocket, ServerWebSocket } from './websocket.js' +export { CLOSE_CODES, CLOSE_MESSAGES } from './message.js' diff --git a/packages/http-websocket/src/message.ts b/packages/http-websocket/src/message.ts new file mode 100644 index 0000000..724cd09 --- /dev/null +++ b/packages/http-websocket/src/message.ts @@ -0,0 +1,236 @@ +import { Uint8ArrayList } from 'uint8arraylist' + +export type MESSAGE_TYPE = 'CONTINUATION' | 'TEXT' | 'BINARY' | 'CONNECTION_CLOSE' | 'PING' | 'PONG' + +const OP_CODES: Record = { + CONTINUATION: 0, + TEXT: 1, + BINARY: 2, + CONNECTION_CLOSE: 8, + PING: 9, + PONG: 10 +} + +const MESSAGE_TYPES: Record = { + 0: 'CONTINUATION', + 1: 'TEXT', + 2: 'BINARY', + 8: 'CONNECTION_CLOSE', + 9: 'PING', + 10: 'PONG' +} + +export const CLOSE_CODES = { + 1000: 'NORMAL_CLOSURE', + 1001: 'GOING_AWAY', + 1002: 'PROTOCOL_ERROR', + 1003: 'UNSUPPORTED_DATA', + 1004: 'RESERVED', + 1005: 'NO_STATUS_RECEIVED', + 1006: 'ABNORMAL_CLOSURE', + 1007: 'INVALID_FRAME_PAYLOAD_DATA', + 1008: 'POLICY_VIOLATION', + 1009: 'MESSAGE_TOO_BIG', + 1010: 'MANDATORY_EXT', + 1011: 'INTERNAL_SERVER_ERROR', + 1015: 'TLS_HANDSHAKE' +} + +export const CLOSE_MESSAGES = { + NORMAL_CLOSURE: 1000, + GOING_AWAY: 1001, + PROTOCOL_ERROR: 1002, + UNSUPPORTED_DATA: 1003, + RESERVED: 1004, + NO_STATUS_RECEIVED: 1005, + ABNORMAL_CLOSURE: 1006, + INVALID_FRAME_PAYLOAD_DATA: 1007, + POLICY_VIOLATION: 1008, + MESSAGE_TOO_BIG: 1009, + MANDATORY_EXT: 1010, + INTERNAL_SERVER_ERROR: 1011, + TLS_HANDSHAKE: 1015 +} + +interface Message { + type: MESSAGE_TYPE + data?: Uint8Array +} + +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +// +-+-+-+-+------+-+-------------+-------------------------------+ +// |F|R|R|R|opcode|M| Payload len | Extended payload length | +// |I|S|S|S| (4) |A| (7) | (16/64) | +// |N|V|V|V| |S| | (if payload len==126/127) | +// | |1|2|3| |K| | | +// +-+-+-+-+------+-+-------------+ - - - - - - - - - - - - - - - + +// | Extended payload length continued, if payload len == 127 | +// + - - - - - - - - - - - - - - -+-------------------------------+ +// | |Masking-key, if MASK set to 1 | +// +------------------------------+-------------------------------+ +// | Masking-key (continued) | Payload Data | +// +------------------------------- - - - - - - - - - - - - - - - + +// : Payload Data continued ... : +// +- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +// | Payload Data continued ... | +// +--------------------------------------------------------------+ + +export function decodeMessage (buf: Uint8ArrayList): Message | undefined { + let offset = 0 + + if (buf.byteLength < (offset + 1)) { + return + } + + const byte0 = buf.get(offset) + const opcode = (byte0 & 0b00001111) + offset++ + + if (MESSAGE_TYPES[opcode] == null) { + throw new Error(`Unknown opcode: ${opcode}`) + } + + if (buf.byteLength < (offset + 1)) { + return + } + + const byte1 = buf.get(offset) + const isMasked = (byte1 & 0b10000000) === 0b10000000 + let length = (byte1 & 0b01111111) + offset++ + + if (length === 126) { + if (buf.byteLength < (offset + 2)) { + return + } + + length = buf.getUint16(offset) + offset += 2 + } else if (length === 127) { + if (buf.byteLength < (offset + 8)) { + return + } + + length = buf.getUint32(offset) + offset += 8 + } + + if (length === 0) { + buf.consume(offset) + + return { + type: MESSAGE_TYPES[opcode] + } + } + + let mask: Uint8Array | undefined + + if (isMasked) { + // check if we have the whole mask + if (buf.byteLength < (offset + 4)) { + return + } + + mask = buf.subarray(offset, offset + 4) + offset += 4 + } + + // check if we have all the data + if (buf.byteLength < (offset + length)) { + return + } + + let data = buf.subarray(offset, offset + length) + offset += length + + if (mask != null) { + data = applyMask(data, mask) + } + + buf.consume(offset) + + return { + type: MESSAGE_TYPES[opcode], + data + } +} + +function applyMask (data: Uint8Array, mask: Uint8Array): Uint8Array { + let m = 0 + + for (let i = 0; i < data.byteLength; i++) { + data[i] = data[i] ^ mask[m] + + m++ + if (m === mask.byteLength) { + m = 0 + } + } + + return data +} + +export async function * decodeMessages (source: AsyncGenerator): AsyncGenerator { + const buffer = new Uint8ArrayList() + + for await (const buf of source) { + buffer.append(buf) + + const message = decodeMessage(buffer) + + if (message != null) { + yield message + } + } +} + +export function encodeMessage (opcode: MESSAGE_TYPE, data?: Uint8Array, maskData?: boolean): Uint8ArrayList { + const fin = true + const message = new Uint8ArrayList( + Uint8Array.from([ + (fin ? 128 : 0) | OP_CODES[opcode] + ]) + ) + + const length = data?.byteLength ?? 0 + + if (length < 126) { + message.append( + Uint8Array.from([ + length | (maskData === true ? 128 : 0) + ]) + ) + } else if (length < 65_535) { + const l = new Uint8ArrayList( + new Uint8Array(3) + ) + l.set(0, 126 | (maskData === true ? 128 : 0)) + l.setUint16(1, length) + + message.append(l) + } else if (length < 18_446_744_073_709_552_000) { + const l = new Uint8ArrayList( + new Uint8Array(9) + ) + l.set(0, 127 | (maskData === true ? 128 : 0)) + l.setUint32(1, length) + + message.append(l) + } else { + throw new Error('Payload too large') + } + + if (maskData === true && data != null) { + const maskingKey = Uint8Array.from([0, 0, 0, 0]) + message.append(maskingKey) + + data = applyMask(data, maskingKey) + } + + if (data != null) { + message.append(data) + } + + return message +} diff --git a/packages/http-websocket/src/utils.ts b/packages/http-websocket/src/utils.ts new file mode 100644 index 0000000..ec4e801 --- /dev/null +++ b/packages/http-websocket/src/utils.ts @@ -0,0 +1,130 @@ +import { HTTPParser } from '@achingbrain/http-parser-js' +import { Response, BAD_REQUEST, toUint8Array, writeHeaders, getServerUpgradeHeaders } from '@libp2p/http-utils' +import { InvalidParametersError } from '@libp2p/interface' +import { base64pad } from 'multiformats/bases/base64' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { StreamWebSocket } from './websocket.js' +import type { HeaderInfo } from '@libp2p/http-utils' +import type { AbortOptions, Stream } from '@libp2p/interface' +import type { ByteStream } from 'it-byte-stream' + +export function toBytes (data: string | Blob | Uint8Array | ArrayBuffer | DataView): Uint8Array | Promise { + if (data instanceof Uint8Array || data instanceof ArrayBuffer || data instanceof DataView) { + return toUint8Array(data) + } + + if (typeof data === 'string') { + return uint8ArrayFromString(data) + } + + if (data instanceof Blob) { + return data.arrayBuffer() + .then(buf => toUint8Array(buf)) + } + + throw new InvalidParametersError('Unsupported data type') +} + +export class CodeError extends Error { + public readonly code: number + + constructor (message: string, code?: number) { + super(message) + this.code = code ?? 0 + } +} + +export async function readResponse (bytes: ByteStream, options: AbortOptions): Promise { + return new Promise((resolve, reject) => { + let readHeaders = false + + const parser = new HTTPParser('RESPONSE') + parser[HTTPParser.kOnHeadersComplete] = (info) => { + readHeaders = true + + const headers: Array<[string, string]> = [] + + for (let i = 0; i < info.headers.length; i += 2) { + headers.push([info.headers[i], info.headers[i + 1]]) + } + + resolve(new Response(null, { + status: info.statusCode, + statusText: info.statusMessage, + headers: new Headers(headers) + })) + } + + Promise.resolve() + .then(async () => { + while (true) { + if (readHeaders) { + break + } + + const chunk = await bytes.read(options) + + if (chunk == null) { + throw new Error('Stream ended before headers were received') + } + + parser.execute(chunk.subarray(), 0, chunk.byteLength) + } + }) + .catch((err: Error) => { + reject(err) + }) + }) +} + +/** + * Implements the WebSocket handshake from the client's perspective + */ +export async function * performClientUpgrade (url: URL, protocols: string[] = [], headers: Headers): AsyncGenerator { + const webSocketKey = base64pad.encode( + crypto.getRandomValues(new Uint8Array(16)) + ).substring(1) + + headers.set('host', url.hostname) + headers.set('connection', 'upgrade') + headers.set('upgrade', 'websocket') + headers.set('pragma', 'no-cache') + headers.set('cache-control', 'no-cache') + headers.set('sec-websocket-version', '13') + headers.set('sec-websocket-key', webSocketKey) + + if (protocols.length > 0) { + headers.set('sec-websocket-protocol', protocols.join(', ')) + } + + yield uint8ArrayFromString([ + `GET ${url.pathname ?? '/'} HTTP/1.1`, + ...[...headers.entries()].map(([key, value]) => `${key}: ${value}`), + '', + '' + ].join('\r\n')) +} + +/** + * Implements the WebSocket handshake from the server's perspective + */ +export async function * performServerUpgrade (headers: Headers | Record): AsyncGenerator { + try { + const responseHeaders = await getServerUpgradeHeaders(headers) + + const message = [ + 'HTTP/1.1 101 Switching Protocols', + ...writeHeaders(responseHeaders), + '', + '' + ] + + yield uint8ArrayFromString(message.join('\r\n')) + } catch { + yield BAD_REQUEST + } +} + +export function streamToWebSocket (info: HeaderInfo, stream: Stream): WebSocket { + return new StreamWebSocket(info, stream) +} diff --git a/packages/http-websocket/src/websocket.ts b/packages/http-websocket/src/websocket.ts new file mode 100644 index 0000000..8432516 --- /dev/null +++ b/packages/http-websocket/src/websocket.ts @@ -0,0 +1,496 @@ +import { getHeaders } from '@libp2p/http-utils' +import { InvalidParametersError, TypedEventEmitter } from '@libp2p/interface' +import { isPromise } from '@libp2p/utils/is-promise' +import { byteStream } from 'it-byte-stream' +import { Uint8ArrayList } from 'uint8arraylist' +import { CloseEvent, ErrorEvent } from './events.js' +import { encodeMessage, decodeMessage, CLOSE_MESSAGES } from './message.js' +import { performClientUpgrade, performServerUpgrade, readResponse, toBytes } from './utils.js' +import type { CloseListener, ErrorListener, MessageListener, OpenListener, WebSocketEvents, WebSocketInit } from './index.js' +import type { MESSAGE_TYPE } from './message.js' +import type { HeaderInfo } from '@libp2p/http-utils' +import type { AbortOptions, Stream } from '@libp2p/interface' +import type { ConnectionManager } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { ByteStream } from 'it-byte-stream' +import type { IncomingMessage } from 'node:http' +import type { Duplex } from 'node:stream' + +const DATA_MESSAGES: MESSAGE_TYPE[] = ['BINARY', 'TEXT', 'CONTINUATION'] +const MAX_MESSAGE_SIZE = 10_485_760 +const DEFAULT_HOST = 'example.com' +export const HTTP_PROTOCOL = '/http/1.1' + +interface AbstractWebSocketInit extends AbortOptions { + protocols?: string[] + isClient?: boolean + maxMessageSize?: number + headers?: Headers +} + +abstract class AbstractWebSocket extends TypedEventEmitter { + public readonly binaryType: 'arraybuffer' | 'blob' = 'arraybuffer' + public bufferedAmount = 0 + public extensions = '' + public protocol: string = '' + public readyState: number + public url: string + + public CONNECTING: 0 = 0 + public OPEN: 1 = 1 + public CLOSING: 2 = 2 + public CLOSED: 3 = 3 + + private _onclose?: CloseListener + private _onerror?: ErrorListener + private _onmessage?: MessageListener + private _onopen?: OpenListener + + private sentClose: boolean + private readonly isClient: boolean + private readonly buffer: Uint8ArrayList + private readonly maxMessageSize: number + protected readonly _url?: URL + protected readonly closeController: AbortController + + constructor (url: URL, init: AbstractWebSocketInit = {}) { + super() + + this.readyState = this.CONNECTING + this.url = url.pathname + this.sentClose = false + this.isClient = init.isClient ?? true + this.buffer = new Uint8ArrayList() + this.closeController = new AbortController() + this.maxMessageSize = init.maxMessageSize ?? MAX_MESSAGE_SIZE + } + + send (data: string | Blob | Uint8Array | ArrayBuffer | DataView): void { + if (this.readyState !== this.OPEN) { + throw new Error('WebSocket was not open') + } + + const b = toBytes(data) + + if (isPromise(b)) { + b.then(b => { + this._send('BINARY', b) + }) + .catch(err => { + this._errored(err) + }) + } else { + this._send('BINARY', b) + } + } + + _send (type: MESSAGE_TYPE, data?: Uint8Array): void { + if (this.readyState !== this.OPEN) { + return + } + + const message = encodeMessage(type, data, this.isClient) + + const byteLength = message.byteLength + this.bufferedAmount += byteLength + + this._write(message, (err) => { + this.bufferedAmount -= byteLength + + if (err != null) { + this._errored(err) + } + }) + } + + close (code?: number, reason?: string): void { + if (this.readyState !== this.OPEN) { + throw new Error('WebSocket was not open') + } + + this.readyState = this.CLOSING + this.sentClose = true + this._send('CONNECTION_CLOSE') + } + + _errored (err: Error): void { + this.readyState = this.CLOSED + this.dispatchEvent(new ErrorEvent(err)) + } + + set onclose (listener: CloseListener) { + this._onclose = listener + this.addEventListener('close', listener) + } + + get onclose (): CloseListener | null { + return this._onclose ?? null + } + + set onerror (listener: ErrorListener) { + this._onerror = listener + this.addEventListener('error', listener) + } + + get onerror (): ErrorListener | null { + return this._onerror ?? null + } + + set onmessage (listener: MessageListener) { + this._onmessage = listener + this.addEventListener('message', listener) + } + + get onmessage (): MessageListener | null { + return this._onmessage ?? null + } + + set onopen (listener: OpenListener) { + this._onopen = listener + this.addEventListener('open', listener) + } + + get onopen (): OpenListener | null { + return this._onopen ?? null + } + + protected _push (buf: Uint8Array | Uint8ArrayList): void { + this.buffer.append(buf) + + if (this.buffer.byteLength > this.maxMessageSize) { + this.close(CLOSE_MESSAGES.MESSAGE_TOO_BIG, 'Max message size exceeded') + return + } + + while (true) { + const message = decodeMessage(this.buffer) + + if (message == null) { + break + } + + if (DATA_MESSAGES.includes(message.type) && message.data != null) { + let data: Blob | ArrayBuffer | ArrayBufferLike + + if (this.binaryType === 'blob') { + data = new Blob([message.data]) + } else { + if (message.data.byteOffset === 0 && message.data.byteLength === message.data.buffer.byteLength) { + // Uint8Array aligns with underlying ArrayBuffer + data = message.data.buffer + } else { + // Uint8Array is a view on a larger ArrayBuffer, copy data before + // emitting. This is inefficient and slow but that's WebSockets + data = new ArrayBuffer(message.data.byteLength) + new Uint8Array(data, 0, data.byteLength).set(message.data) + } + } + + this.dispatchEvent(new MessageEvent('message', { + data, + origin: this._url?.hostname + })) + } + + // respond to pings + if (message.type === 'PING') { + this._send('PONG', message.data) + } + + // close handshake + if (message.type === 'CONNECTION_CLOSE') { + if (!this.sentClose) { + this.close() + } + + this.closeController.abort() + this._close(undefined, () => { + this.readyState = this.CLOSED + this.dispatchEvent(new CloseEvent('close')) + }) + } + } + } + + /** + * To be invoked when the underlying transport is closed by the remote end + */ + protected _remoteClosed (err?: Error): void { + this.readyState = this.CLOSING + this._close(err, () => { + this.readyState = this.CLOSED + this.dispatchEvent(new CloseEvent('close')) + }) + } + + /** + * Invoked when data is to be sent over the socket, the passed callback should + * be called when the data has been written + */ + protected abstract _write (buf: Uint8ArrayList, cb: (err?: Error | null) => void): void + + /** + * The implementation of this method should close the underlying transport. If + * an error is passed, the transport should be closed immediately. + * + * The passed callback should be invoked when the transport has closed + */ + protected abstract _close (err: Error | undefined, cb: () => void): void +} + +export class ServerWebSocket extends AbstractWebSocket { + private readonly duplex: Duplex + + constructor (request: IncomingMessage, duplex: Duplex, init: AbstractWebSocketInit = {}) { + super(new URL(`http://${request.headers.host ?? DEFAULT_HOST}${request.url}`), { + ...init, + isClient: false + }) + + this.duplex = duplex + + this.duplex.on('data', (buf) => { + this._push(buf) + }) + this.duplex.on('close', () => { + this.close() + }) + this.duplex.on('error', (err) => { + this.close(CLOSE_MESSAGES.ABNORMAL_CLOSURE, err.message) + }) + + Promise.resolve().then(async () => { + for await (const buf of performServerUpgrade(request.headers)) { + this.duplex.write(buf) + } + + this.readyState = this.OPEN + this.dispatchEvent(new Event('open')) + }) + .catch(err => { + this.duplex.destroy(err) + }) + } + + _write (buf: Uint8ArrayList, cb: (err?: Error | null) => void): void { + this.duplex.write(buf.subarray(), cb) + } + + _close (err: Error, cb: () => void): void { + this.readyState = this.CLOSED + this.duplex.destroy(err) + cb() + } +} + +export class StreamWebSocket extends AbstractWebSocket { + private readonly bytes: ByteStream + + constructor (info: HeaderInfo, stream: Stream, init?: AbstractWebSocketInit) { + super(new URL(`http://${info.headers.get('host') ?? DEFAULT_HOST}${info.url}`), { + ...init, + isClient: false + }) + + this.bytes = byteStream(stream) + + Promise.resolve() + .then(async () => { + for await (const buf of performServerUpgrade(info.headers)) { + await this.bytes.write(buf) + } + + this.readyState = this.OPEN + this.dispatchEvent(new Event('open')) + + while (true) { + const buf = await this.bytes.read() + + if (buf == null) { + this._remoteClosed() + break + } + + this._push(buf) + } + }) + .catch(err => { + this._errored(err) + }) + } + + _write (buf: Uint8ArrayList, cb: (err?: Error | null) => void): void { + this.bytes?.write(buf) + .then(() => { + cb() + }, err => { + cb(err) + }) + } + + _close (err: Error, cb: () => void): void { + const stream = this.bytes?.unwrap() + + if (err != null) { + stream?.abort(err) + cb() + } else { + stream?.close() + .then(() => { + cb() + }, err => { + stream.abort(err) + cb() + }) + } + } +} + +export class RequestWebSocket extends AbstractWebSocket { + private readonly writer: WritableStreamDefaultWriter + private readonly writable: WritableStream + + constructor (request: Request, writable: WritableStream, init: AbstractWebSocketInit = {}) { + super(new URL(request.url), { + ...init, + isClient: false + }) + + if (request.body == null) { + throw new InvalidParametersError('Request body cannot be null') + } + + this.readyState = this.OPEN + this.writable = writable + this.writer = writable.getWriter() + const reader = request.body.getReader() + + Promise.resolve() + .then(async () => { + this.dispatchEvent(new Event('open')) + + while (true) { + const { value, done } = await reader.read() + + if (value != null) { + this._push(value) + } + + if (done) { + this._remoteClosed() + break + } + } + }) + .catch(err => { + this._errored(err) + }) + } + + _write (buf: Uint8ArrayList, cb: (err?: Error | null) => void): void { + this.writer?.write(buf) + .then(() => { + cb() + }, err => { + cb(err) + }) + } + + _close (err: Error, cb: () => void): void { + if (err != null) { + this.writable.abort(err) + .then(() => { + cb() + }, () => { + cb() + }) + } else { + this.writable.close() + .then(() => { + cb() + }, () => { + cb() + }) + } + } +} + +export class WebSocket extends AbstractWebSocket { + private bytes?: ByteStream + + constructor (mas: Multiaddr[], url: URL, connectionManager: ConnectionManager, init: WebSocketInit) { + super(url, { + ...init, + isClient: true + }) + + Promise.resolve() + .then(async () => { + const connection = await connectionManager.openConnection(mas, init) + const stream = await connection.newStream(HTTP_PROTOCOL, init) + this.bytes = byteStream(stream) + + for await (const buf of performClientUpgrade(url, init.protocols, getHeaders(init))) { + await this.bytes.write(buf) + } + + const res = await readResponse(this.bytes, {}) + + if (res.status !== 101) { + throw new Error('Invalid WebSocket handshake - response status ' + res.status) + } + + await init.onHandshakeResponse?.(res) + + // if a protocol was selected by the server, expose it + this.protocol = res.headers.get('Sec-WebSocket-Protocol') ?? '' + + this.readyState = this.OPEN + this.dispatchEvent(new Event('open')) + + for await (const buf of stream.source) { + this._push(buf) + } + }) + .catch(err => { + this._errored(err) + }) + } + + _write (buf: Uint8ArrayList, cb: (err?: Error | null) => void): void { + if (this.bytes == null) { + cb(new Error('WebSocket was not open')) + return + } + + this.bytes.write(buf) + .then(() => { + cb() + }, (err) => { + cb(err) + }) + } + + _close (err: Error | undefined, cb: () => void): void { + if (this.bytes == null) { + cb() + return + } + + const stream = this.bytes.unwrap() + + if (err != null) { + stream.abort(err) + cb() + return + } + + stream.close() + .catch((err) => { + stream.abort(err) + }) + .finally(() => { + cb() + }) + } +} diff --git a/packages/http-websocket/test/index.spec.ts b/packages/http-websocket/test/index.spec.ts new file mode 100644 index 0000000..60d708b --- /dev/null +++ b/packages/http-websocket/test/index.spec.ts @@ -0,0 +1,5 @@ +describe('@libp2p/http-websocket', () => { + it('should run a test', () => { + + }) +}) diff --git a/packages/http-websocket/test/message.spec.ts b/packages/http-websocket/test/message.spec.ts new file mode 100644 index 0000000..2722e80 --- /dev/null +++ b/packages/http-websocket/test/message.spec.ts @@ -0,0 +1,113 @@ +import { expect } from 'aegir/chai' +import { Uint8ArrayList } from 'uint8arraylist' +import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string' +import { decodeMessage, encodeMessage } from '../src/message.js' + +describe('websocket messages', () => { + it('should encode and decode a small message', () => { + const data = Uint8Array.from([0, 1, 2, 3, 4]) + const input = encodeMessage('BINARY', data, true) + + const output = decodeMessage(new Uint8ArrayList(input.subarray())) + expect(output).to.have.property('type', 'BINARY') + expect(output).to.have.property('data').that.equalBytes(data) + }) + + it('should encode and decode a medium message', () => { + const data = new Uint8Array(49_391).map((v, i) => i) + const input = encodeMessage('BINARY', data, true) + + const output = decodeMessage(new Uint8ArrayList(input.subarray())) + expect(output).to.have.property('type', 'BINARY') + expect(output).to.have.property('data').that.equalBytes(data) + }) + + it('should encode and decode a large message', () => { + const data = new Uint8Array(123_392_198).map((v, i) => i) + const input = encodeMessage('BINARY', data, true) + + const output = decodeMessage(new Uint8ArrayList(input.subarray())) + expect(output).to.have.property('type', 'BINARY') + expect(output).to.have.property('data').that.equalBytes(data) + }) + + describe('rfc6455 examples', () => { + it('A single-frame unmasked text message', () => { + const input = Uint8Array.from([ + 0x81, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f + ]) + const output = decodeMessage(new Uint8ArrayList(input)) + + expect(output).to.have.property('type', 'TEXT') + expect(output).to.have.property('data').that.equalBytes(uint8ArrayFromString('Hello')) + }) + + it('A single-frame masked text message', () => { + const input = Uint8Array.from([ + 0x81, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58 + ]) + const output = decodeMessage(new Uint8ArrayList(input)) + + expect(output).to.have.property('type', 'TEXT') + expect(output).to.have.property('data').that.equalBytes(uint8ArrayFromString('Hello')) + }) + + it('A fragmented unmasked text message', () => { + const input1 = Uint8Array.from([ + 0x01, 0x03, 0x48, 0x65, 0x6c + ]) + const output1 = decodeMessage(new Uint8ArrayList(input1)) + + expect(output1).to.have.property('type', 'TEXT') + expect(output1).to.have.property('data').that.equalBytes(uint8ArrayFromString('Hel')) + + const input2 = Uint8Array.from([ + 0x80, 0x02, 0x6c, 0x6f + ]) + const output2 = decodeMessage(new Uint8ArrayList(input2)) + + expect(output2).to.have.property('type', 'CONTINUATION') + expect(output2).to.have.property('data').that.equalBytes(uint8ArrayFromString('lo')) + }) + + it('Unmasked Ping request and masked Ping response', () => { + const input1 = Uint8Array.from([ + 0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f + ]) + const output1 = decodeMessage(new Uint8ArrayList(input1)) + + expect(output1).to.have.property('type', 'PING') + expect(output1).to.have.property('data').that.equalBytes(uint8ArrayFromString('Hello')) + + const input2 = Uint8Array.from([ + 0x8a, 0x85, 0x37, 0xfa, 0x21, 0x3d, 0x7f, 0x9f, 0x4d, 0x51, 0x58 + ]) + const output2 = decodeMessage(new Uint8ArrayList(input2)) + + expect(output2).to.have.property('type', 'PONG') + expect(output2).to.have.property('data').that.equalBytes(uint8ArrayFromString('Hello')) + }) + + it('256 bytes binary message in a single unmasked frame', () => { + const data = new Uint8Array(256).map((v, i) => i) + const input = Uint8Array.from([ + 0x82, 0x7E, 0x01, 0x00 + ]) + const output = decodeMessage(new Uint8ArrayList(input, data)) + + expect(output).to.have.property('type', 'BINARY') + expect(output).to.have.property('data').that.equalBytes(data) + }) + + it.skip('64KiB binary message in a single unmasked frame', () => { + const data = new Uint8Array(Math.pow(2, 16)).map((v, i) => i) + const input = Uint8Array.from([ + 0x82, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 + ]) + const output = decodeMessage(new Uint8ArrayList(input, data)) + + expect(output).to.have.property('type', 'BINARY') + expect(output).to.have.property('data').that.equalBytes(data) + }) + }) +}) diff --git a/packages/http-websocket/tsconfig.json b/packages/http-websocket/tsconfig.json new file mode 100644 index 0000000..7cfc2d8 --- /dev/null +++ b/packages/http-websocket/tsconfig.json @@ -0,0 +1,15 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ], + "references": [ + { + "path": "../http-utils" + } + ] +} diff --git a/packages/http-websocket/typedoc.json b/packages/http-websocket/typedoc.json new file mode 100644 index 0000000..db0b074 --- /dev/null +++ b/packages/http-websocket/typedoc.json @@ -0,0 +1,6 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts" + ] +} diff --git a/packages/http/CODE_OF_CONDUCT.md b/packages/http/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..6b0fa54 --- /dev/null +++ b/packages/http/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/packages/http/LICENSE-APACHE b/packages/http/LICENSE-APACHE new file mode 100644 index 0000000..b09cd78 --- /dev/null +++ b/packages/http/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/packages/http/LICENSE-MIT b/packages/http/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/http/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/packages/http/README.md b/packages/http/README.md new file mode 100644 index 0000000..c2ad7b2 --- /dev/null +++ b/packages/http/README.md @@ -0,0 +1,76 @@ +# @libp2p/http + +[![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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> Accept HTTP requests over libp2p streams or use libp2p protocols over HTTP + +# About + + + +This module allows you to use HTTP requests as a transport for libp2p +protocols (libp2p over HTTP), and also libp2p streams as a transport for HTTP +requests (HTTP over libp2p). + +It integrates with existing Node.js friendly HTTP frameworks such as +[express](https://expressjs.com/) and [Fastify](https://fastify.dev) as well +as [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)/ +[Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)-based +frameworks like [Hono](https://hono.dev/). + +It even allows creating Node.js-style [http.Server](https://nodejs.org/api/http.html#class-httpserver)s +and [WebSocketServer](https://github.com/websockets/ws/blob/HEAD/doc/ws.md#class-websocketserver)s +in browsers to truly realize the power of the distributed web. + +In addition to URL-based addressing, it can use a libp2p PeerId and/or +multiaddr(s) and lets libp2p take care of the routing, thus taking advantage +of features like multi-routes, NAT traversal and stream multiplexing over a +single connection. + +Check out the [examples](https://github.com/libp2p/js-libp2p-http/tree/main/examples) +for how you can use this in your applications! + +# Install + +```console +$ npm i @libp2p/http +``` + +## Browser ` +``` + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/blob/main/packages/http/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/packages/http/package.json b/packages/http/package.json new file mode 100644 index 0000000..68c49a3 --- /dev/null +++ b/packages/http/package.json @@ -0,0 +1,182 @@ +{ + "name": "@libp2p/http", + "version": "0.0.0", + "description": "Accept HTTP requests over libp2p streams or use libp2p protocols over HTTP", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/http#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/issues" + }, + "publishConfig": { + "access": "public", + "provenance": true + }, + "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" + }, + "./middleware": { + "types": "./dist/src/middleware/index.d.ts", + "import": "./dist/src/middleware/index.js" + }, + "./routes": { + "types": "./dist/src/routes/index.d.ts", + "import": "./dist/src/routes/index.js" + } + }, + "release": { + "branches": [ + "main" + ], + "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": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check", + "release": "aegir release" + }, + "dependencies": { + "@libp2p/http-fetch": "^2.0.0", + "@libp2p/http-peer-id-auth": "~0.0.0", + "@libp2p/http-utils": "~0.0.0", + "@libp2p/http-websocket": "~0.0.0", + "@libp2p/interface": "^2.10.2", + "@libp2p/interface-internal": "^2.3.14", + "@multiformats/multiaddr": "^12.4.0", + "cookie": "^1.0.2", + "undici": "^6.21.3" + }, + "devDependencies": { + "aegir": "^47.0.16" + }, + "browser": { + "./dist/src/http.js": "./dist/src/http.browser.js" + }, + "sideEffects": false +} diff --git a/packages/http/src/constants.ts b/packages/http/src/constants.ts new file mode 100644 index 0000000..8dab3b0 --- /dev/null +++ b/packages/http/src/constants.ts @@ -0,0 +1,5 @@ +export const HTTP_PROTOCOL = '/http/1.1' +export const PEER_ID_AUTH_SCHEME = 'libp2p-PeerID' +export const HTTP_PEER_ID_AUTH_PROTO = '/http-peer-id-auth/1.0.0' +export const DEFAULT_COOKIE_EXPIRY_CHECK_INTERVAL = 60_000 +export const WEBSOCKET_HANDLER = Symbol.for('@libp2p/http/websocket-handler') diff --git a/packages/http/src/http.browser.ts b/packages/http/src/http.browser.ts new file mode 100644 index 0000000..0b260cb --- /dev/null +++ b/packages/http/src/http.browser.ts @@ -0,0 +1,206 @@ +import { fetch } from '@libp2p/http-fetch' +import { getHeaders, getHost, stripHTTPPath, toResource } from '@libp2p/http-utils' +import { WebSocket } from '@libp2p/http-websocket' +import { UnsupportedOperationError, serviceCapabilities, start, stop } from '@libp2p/interface' +import { HTTP_PROTOCOL } from './constants.js' +import { Cookies } from './middleware/cookies.js' +import { Origin } from './middleware/origin.js' +import { HTTPRegistrar } from './registrar.js' +import { prepareAndConnect, prepareAndSendRequest, processResponse } from './utils.js' +import { WELL_KNOWN_PROTOCOLS_PATH } from './index.js' +import type { HTTPInit, HTTP as HTTPInterface, ProtocolMap, FetchInit, HTTPRoute, ConnectInit, MiddlewareOptions } from './index.js' +import type { ComponentLogger, Logger, PeerId, PrivateKey, Startable } from '@libp2p/interface' +import type { ConnectionManager, Registrar } from '@libp2p/interface-internal' +import type { AbortOptions, Multiaddr } from '@multiformats/multiaddr' + +export interface HTTPComponents { + privateKey: PrivateKey + registrar: Registrar + connectionManager: ConnectionManager + logger: ComponentLogger +} + +export class HTTP implements HTTPInterface, Startable { + private readonly log: Logger + protected readonly components: HTTPComponents + private readonly httpRegistrar: HTTPRegistrar + private readonly origin: Origin + private readonly cookies: Cookies + + constructor (components: HTTPComponents, init: HTTPInit = {}) { + this.components = components + this.log = components.logger.forComponent('libp2p:http') + this.httpRegistrar = new HTTPRegistrar(components, init) + this.origin = new Origin() + this.cookies = new Cookies(components, init) + } + + readonly [Symbol.toStringTag] = '@libp2p/http' + + readonly [serviceCapabilities]: string[] = [ + '@libp2p/http' + ] + + async start (): Promise { + await start( + this.httpRegistrar + ) + } + + async stop (): Promise { + await stop( + this.httpRegistrar + ) + } + + agent (...args: any[]): any { + throw new UnsupportedOperationError('This method is not supported in browsers') + } + + dispatcher (...args: any[]): any { + throw new UnsupportedOperationError('This method is not supported in browsers') + } + + async connect (resource: string | URL | PeerId | Multiaddr | Multiaddr[], init: ConnectInit = {}): Promise { + const url = toResource(resource) + const headers = getHeaders(init) + const opts: MiddlewareOptions = { + ...init, + headers, + method: 'GET', + middleware: init.middleware?.map(fn => fn(this.components)) ?? [] + } + + headers.set('connection', 'upgrade') + headers.set('upgrade', 'websocket') + + return prepareAndConnect(url, opts, async () => { + if (url instanceof URL) { + const socket = new globalThis.WebSocket(url, init.protocols) + socket.binaryType = 'arraybuffer' + + return socket + } + + // strip http-path tuple but record the value if set + const { addresses, httpPath } = stripHTTPPath(url) + + return new WebSocket( + addresses, + new URL(`http://${getHost(url, opts.headers)}${decodeURIComponent(httpPath)}`), + this.components.connectionManager, + opts + ) + }) + } + + async fetch (resource: string | URL | PeerId | Multiaddr | Multiaddr[], init: FetchInit = {}): Promise { + const url = toResource(resource) + const opts: MiddlewareOptions = { + ...init, + headers: getHeaders(init), + method: 'GET', + middleware: [ + this.origin, + this.cookies, + ...init.middleware?.map(fn => fn(this.components)) ?? [] + ] + } + + const response = await prepareAndSendRequest(url, opts, async () => { + return this.sendRequest(url, init) + }) + + return processResponse(url, opts, response) + } + + async connectProtocol (resource: string | URL | PeerId | Multiaddr | Multiaddr[], protocol: string, init?: ConnectInit): Promise { + const path = await this.getProtocolPath(resource, protocol, init) + const url = toResource(resource, path) + + return this.connect(url, init) + } + + async fetchProtocol (resource: string | URL | PeerId | Multiaddr | Multiaddr[], protocol: string, init: FetchInit = {}): Promise { + const path = await this.getProtocolPath(resource, protocol, init) + const url = toResource(resource, path) + + return this.fetch(url, init) + } + + async getSupportedProtocols (resource: string | URL | PeerId | Multiaddr | Multiaddr[], options: AbortOptions = {}): Promise { + const url = toResource(resource, WELL_KNOWN_PROTOCOLS_PATH) + const resp = await this.fetch(url, { + method: 'GET', + headers: { + Accept: 'application/json' + }, + signal: options.signal + }) + + if (resp.status !== 200) { + throw new Error(`Unexpected status code: ${resp.status}`) + } + + return resp.json() + } + + async getProtocolPath (peer: string | URL | PeerId | Multiaddr | Multiaddr[], protocol: string, options: AbortOptions = {}): Promise { + const peerMeta = await this.getSupportedProtocols(peer, options) + + if (peerMeta[protocol] == null) { + throw new Error(`Peer does not serve protocol: ${protocol}`) + } + + return peerMeta[protocol].path + } + + canHandle (req: { url?: string }): boolean { + return this.httpRegistrar.canHandle(req) + } + + async onRequest (req: Request): Promise { + return this.httpRegistrar.onRequest(req) + } + + onWebSocket (ws: globalThis.WebSocket): void { + this.httpRegistrar.onWebSocket(ws) + } + + handle (protocol: string, handler: HTTPRoute): void { + this.httpRegistrar.handle(protocol, handler) + } + + unhandle (protocol: string): void { + this.httpRegistrar.unhandle(protocol) + } + + getProtocolMap (): ProtocolMap { + return this.httpRegistrar.getProtocolMap() + } + + private async sendRequest (resource: Multiaddr[] | URL, init: FetchInit): Promise { + if (resource instanceof URL) { + this.log('making request with global fetch') + return globalThis.fetch(resource, init) + } + + this.log('making request with libp2p fetch') + const host = getHost(resource, getHeaders(init)) + + // strip http-path tuple but record the value if set + const { addresses, httpPath } = stripHTTPPath(resource) + + const connection = await this.components.connectionManager.openConnection(addresses, { + signal: init.signal ?? undefined + }) + const stream = await connection.newStream(HTTP_PROTOCOL, { + signal: init.signal ?? undefined + }) + + return fetch(stream, new URL(`http://${host}${decodeURIComponent(httpPath)}`), { + ...init, + logger: this.components.logger + }) + } +} diff --git a/packages/http/src/http.ts b/packages/http/src/http.ts new file mode 100644 index 0000000..5aad930 --- /dev/null +++ b/packages/http/src/http.ts @@ -0,0 +1,107 @@ +import { Agent as NodeAgent } from 'node:http' +import { streamToSocket, toResource } from '@libp2p/http-utils' +import { isPeerId } from '@libp2p/interface' +import { Agent as UndiciAgent } from 'undici' +import { HTTP_PROTOCOL } from './constants.js' +import { HTTP as HTTPBrowser } from './http.browser.js' +import type { HTTP as HTTPInterface } from './index.js' +import type { AbortOptions, PeerId } from '@libp2p/interface' +import type { ConnectionManager, Registrar } from '@libp2p/interface-internal' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Agent, AgentOptions } from 'node:http' +import type { Socket, TcpNetConnectOpts } from 'node:net' +import type { Dispatcher } from 'undici' + +export type { HTTPComponents } from './http.browser.js' + +async function createConnection (connectionManager: ConnectionManager, peer: PeerId | Multiaddr | Multiaddr[], options?: AbortOptions): Promise { + const connection = await connectionManager.openConnection(peer, options) + const stream = await connection.newStream(HTTP_PROTOCOL, options) + + return streamToSocket(stream, connection) +} + +interface HTTPDispatcherComponents { + connectionManager: ConnectionManager +} + +interface HTTPDispatcherInit extends UndiciAgent.Options { + peer: PeerId | Multiaddr | Multiaddr[] +} + +export class Libp2pDispatcher extends UndiciAgent { + constructor (components: HTTPDispatcherComponents, init: HTTPDispatcherInit) { + super({ + ...init, + connect: (options, cb) => { + createConnection(components.connectionManager, init.peer, { + // @ts-expect-error types are wonky + signal: options.timeout != null ? AbortSignal.timeout(options.timeout) : undefined + }) + .then(socket => { + cb(null, socket) + }, err => { + cb(err, null) + }) + } + }) + } +} + +interface HTTPAgentComponents { + connectionManager: ConnectionManager +} + +interface HTTPAgentInit extends AgentOptions { + peer: PeerId | Multiaddr | Multiaddr[] +} + +class Libp2pAgent extends NodeAgent { + public readonly keepAliveMsecs: number = 100 + private readonly components: HTTPAgentComponents + private readonly peer: PeerId | Multiaddr | Multiaddr[] + + constructor (components: HTTPAgentComponents, init: HTTPAgentInit) { + super(init) + this.components = components + this.peer = init.peer + } + + createConnection (options: TcpNetConnectOpts, cb: (err?: Error, socket?: Socket) => void): void { + createConnection(this.components.connectionManager, this.peer, options) + .then(socket => { + cb(undefined, socket) + }, err => { + cb(err) + }) + } +} + +export interface HTTPClientComponents { + registrar: Registrar + connectionManager: ConnectionManager +} + +export class HTTP extends HTTPBrowser implements HTTPInterface { + agent (peer: PeerId | Multiaddr | Multiaddr[], options?: AgentOptions): Agent { + if (!isPeerId(peer) && toResource(peer) instanceof URL) { + return new NodeAgent(options) + } + + return new Libp2pAgent(this.components, { + ...options, + peer + }) + } + + dispatcher (peer: PeerId | Multiaddr | Multiaddr[], options?: UndiciAgent.Options): Dispatcher { + if (!isPeerId(peer) && toResource(peer) instanceof URL) { + return new UndiciAgent(options) + } + + return new Libp2pDispatcher(this.components, { + ...options, + peer + }) + } +} diff --git a/packages/http/src/index.ts b/packages/http/src/index.ts new file mode 100644 index 0000000..9651079 --- /dev/null +++ b/packages/http/src/index.ts @@ -0,0 +1,344 @@ +/** + * @packageDocumentation + * + * This module allows you to use HTTP requests as a transport for libp2p + * protocols (libp2p over HTTP), and also libp2p streams as a transport for HTTP + * requests (HTTP over libp2p). + * + * It integrates with existing Node.js friendly HTTP frameworks such as + * [express](https://expressjs.com/) and [Fastify](https://fastify.dev) as well + * as [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)/ + * [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response)-based + * frameworks like [Hono](https://hono.dev/). + * + * It even allows creating Node.js-style [http.Server](https://nodejs.org/api/http.html#class-httpserver)s + * and [WebSocketServer](https://github.com/websockets/ws/blob/HEAD/doc/ws.md#class-websocketserver)s + * in browsers to truly realize the power of the distributed web. + * + * In addition to URL-based addressing, it can use a libp2p PeerId and/or + * multiaddr(s) and lets libp2p take care of the routing, thus taking advantage + * of features like multi-routes, NAT traversal and stream multiplexing over a + * single connection. + * + * Check out the [examples](https://github.com/libp2p/js-libp2p-http/tree/main/examples) + * for how you can use this in your applications! + */ + +import { HTTP as HTTPClass } from './http.js' +import type { WEBSOCKET_HANDLER } from './constants.js' +import type { HTTPComponents } from './http.js' +import type { HeaderInfo, MiddlewareOptions, Middleware } from '@libp2p/http-utils' +import type { AbortOptions, Connection, PeerId, Stream } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Agent, AgentOptions, IncomingMessage } from 'node:http' +import type { Dispatcher, Agent as UndiciAgent } from 'undici' + +export { WELL_KNOWN_PROTOCOLS_PATH } from './routes/well-known.js' +export { HTTP_PROTOCOL } from './constants.js' + +/** + * Options used to control Fetch request and the initial WebSocket upgrade + * request + */ +export interface HTTPRequestOptions extends AbortOptions { + /** + * A list of request processors that can augment requests - if specified will + * override any processors passed to the `http` service + */ + middleware?: Array<(components: any) => Middleware> + + /** + * The maximum number of bytes that will be parsed as response headers + * + * @default 81_920 + */ + maxHeaderSize?: number + + /** + * If true, verify the server's peer id using PeerId Authentication + * + * @default false + */ + authenticateServer?: boolean +} + +export interface ConnectInit extends HTTPRequestOptions { + /** + * The maximum message size to be sent or received over the socket in bytes + * + * @default 10_485_760 + */ + maxMessageSize?: number + + /** + * Headers to send with the initial upgrade request + */ + headers?: HeadersInit + + /** + * Protocols to send with the upgrade request + */ + protocols?: string[] +} + +export type FetchInit = HTTPRequestOptions & RequestInit + +export interface HTTPRequestHandler { + (req: Request): Promise +} + +export interface WebSocketHandler { + (ws: WebSocket): void +} + +export type ProtocolID = string + +export interface ProtocolDescriptor { + path: string +} + +export type ProtocolMap = Record + +export interface RequestHandlerOptions { + /** + * Specify a path to serve the protocol from. If omitted the protocol name + * will be used. + * + * Paths can be looked up from the protocol map using `getProtocolMap()` or by + * making a GET request to `/.well-known/libp2p/protocols`. + */ + path?: string + + /** + * A list of HTTP verbs this handler will respond to. If the handler is found + * but the request method is not present a 405 will be returned. + * + * @default ['GET'] + */ + methods?: string[] + + /** + * By default all handlers support CORS headers, pass `false` here to disallow + * access to fetch requests. + * + * @default true + */ + cors?: boolean +} + +/** + * Options used to define a HTTP route that can handle requests + */ +export interface RouteOptions { + /** + * Specify a path to serve the protocol from. If omitted the protocol name + * will be used. + * + * Paths can be looked up from the protocol map using `getProtocolMap()` or by + * making a GET request to `/.well-known/libp2p/protocols`. + */ + path?: string + + /** + * A list of HTTP verbs this handler will respond to. If the handler is found + * but the request method is not present a 405 will be returned. + * + * @default ['GET'] + */ + method?: string | string[] + + /** + * By default all handlers support CORS headers, pass `false` here to disallow + * access to fetch requests. + * + * @default true + */ + cors?: boolean +} + +/** + * A simple route that defines a handler function + */ +export interface HandlerRoute extends RouteOptions { + handler: H +} + +/** + * A route that requires initialization before use + */ +export interface ServiceRoute extends RouteOptions { + init(components: any): H +} + +/** + * A WebSocket route can make it's handler available for invocation with a + * pre-upgraded WebSocket object + */ +export interface WebSocketRoute { + [WEBSOCKET_HANDLER]?: WebSocketHandler +} + +/** + * A union of the various route types + */ +export type HTTPRoute = (HandlerRoute | ServiceRoute) & WebSocketRoute + +/** + * HTTP service interface + */ +export interface HTTP { + /** + * Make a request in a similar way to globalThis.fetch. + * + * If the passed `resource` is a string, if it starts with a `/` character it + * will be interpreted as a Multiaddr, otherwise it will be interpreted as a + * URL. + * + * URLs can start with the `multiaddr:` scheme if the global URL class in the + * runtime environment supports it. + */ + fetch(resource: string | URL | PeerId | Multiaddr | Multiaddr[], init?: FetchInit): Promise + + /** + * Open a WebSocket connection to an HTTP server over libp2p. + * + * If the passed `resource` starts with a `/` character, it will be + * interpreted as a Multiaddr, otherwise it will be interpreted as a URL. + * + * URLs can start with the `multiaddr:` scheme if the global URL class in the + * runtime environment supports it. + */ + connect (resource: string | URL | PeerId | Multiaddr | Multiaddr[], init?: ConnectInit): Promise + + /** + * Get a libp2p-enabled Agent for use with node's `http` module. This method + * will throw when not running under Node.js or Electron. + * + * All requests using this Agent will be sent to the peer reachable by the + * peer ID or multiaddr(s) passed as the first argument. + */ + agent (peer: PeerId | Multiaddr | Multiaddr[], options?: AgentOptions): Agent + + /** + * Get a libp2p-enabled Dispatcher for use with the `undici` module. This + * method will throw when not running under Node.js or Electron. + * + * All requests using this Agent will be sent to the peer reachable by the + * peer ID or multiaddr(s) passed as the first argument. + */ + dispatcher (peer: PeerId | Multiaddr | Multiaddr[], options?: UndiciAgent.Options): Dispatcher + + /** + * Look up the path for the protocol and invoke it with the passed arguments. + * + * This is similar in scope to `libp2p.dialProtocol`. + */ + fetchProtocol(resource: string | URL | PeerId | Multiaddr | Multiaddr[], protocol: string, init?: FetchInit): Promise + + /** + * Look up the path for the protocol and create a WebSocket connection to the + * handler. + * + * This is similar in scope to `libp2p.dialProtocol`. + */ + connectProtocol(resource: string | URL | PeerId | Multiaddr | Multiaddr[], protocol: string, init?: ConnectInit): Promise + + /** + * Register a listener for a HTTP protocol + */ + handle (protocol: string, handler: HTTPRoute): void + + /** + * Remove a listener for a HTTP protocol + */ + unhandle (protocol: string): void + + /** + * Return the protocol->path mappings supported by this server + */ + getProtocolMap (): ProtocolMap + + /** + * Returns true if there is a handler registered for the incoming Request or + * WebSocket. + * + * Note - the `.url` property must be set on the WebSocket for this to work. + * Not all server-side WebSocket frameworks do this out of the box so the + * caller may have to add the property. + */ + canHandle (req: Request | IncomingMessage | WebSocket): boolean + + /** + * Handle an incoming HTTP request + */ + onRequest: HTTPRequestHandler + + /** + * Handle an incoming WebSocket + */ + onWebSocket: WebSocketHandler +} + +/** + * A WebServer that can accept incoming libp2p streams and transform them into + * an HTTP request that can be processed + */ +export interface WebServer { + /** + * Accept an incoming request. The headers have already been parsed, the + * stream/connection should be transformed into whatever format the HTTP + * server requires + */ + inject (info: HeaderInfo, stream: Stream, connection: Connection): Promise +} + +export type { MiddlewareOptions, Middleware } + +/** + * Options to configure the HTTP service. + * + * Only required if you want to specify a custom fetch implementation or used to + * provide one if your environment does not have a global fetch. + */ +export interface HTTPInit { + /** + * A server that will receive incoming requests + */ + server?: WebServer + + /** + * How long in ms an auth token for a server will be valid for, defaults to + * one hour + * + * @default 360_000 + */ + authTokenTTL?: number + + /** + * A list of request processors that can augment requests. Middleware passed + * here will be invoked on every outgoing request. + */ + middleware?: Array<(components: any) => Middleware> + + /** + * How often to evict stale cookies from the cache in ms. + * + * Nb. cookies are checked for expiry before sending, this setting just + * prevents persisting cookies indefinitely for servers that are contacted + * infrequently. + * + * @default 60_000 + */ + cookieExpiryCheckInterval?: number +} + +/** + * Create an HTTP service that provides a `fetch` implementation and a way to + * register custom HTTP handlers. + */ +export function http (init: HTTPInit = {}): (components: HTTPComponents) => HTTP { + return (components) => new HTTPClass(components, init) +} + +export { authenticatedRoute, authenticatedWebSocketRoute } from './routes/peer-id-auth.js' +export { webSocketRoute } from './routes/websocket.js' diff --git a/packages/http/src/middleware/cookies.ts b/packages/http/src/middleware/cookies.ts new file mode 100644 index 0000000..b229f2d --- /dev/null +++ b/packages/http/src/middleware/cookies.ts @@ -0,0 +1,140 @@ +import { toURL } from '@libp2p/http-utils' +import cookie from 'cookie' +import type { Middleware, MiddlewareOptions } from '@libp2p/http-utils' +import type { ComponentLogger, Logger } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +interface CookiesComponents { + logger: ComponentLogger +} + +export interface CookiesInit { + cookieExpiryCheckInterval?: number +} + +interface Cookie { + name: string + value: string + expires?: number + domain?: string + path?: string +} + +export class Cookies implements Middleware { + private readonly log: Logger + private readonly cookies: Map + + constructor (components: CookiesComponents, init: CookiesInit = {}) { + this.log = components.logger.forComponent('libp2p:http:cookies') + this.cookies = new Map() + } + + async prepareRequest (resource: URL | Multiaddr[], opts: MiddlewareOptions): Promise { + const credentials = opts.credentials ?? 'same-origin' + + if (credentials === 'omit') { + return + } + + const origin = opts.headers.get('origin') + + if (origin == null || origin === 'null') { + return + } + + const url = toURL(resource, opts.headers) + const cookies = (this.cookies.get(url.hostname) ?? []).filter(cookie => { + if (cookie.expires != null && cookie.expires < Date.now()) { + return false + } + + if (cookie.path != null && !url.pathname.startsWith(cookie.path)) { + return false + } + + return true + }) + .map(cookie => `${cookie.name}=${cookie.value}`) + .join('; ') + + if (cookies.length > 0) { + opts.headers.set('cookie', cookies) + } + } + + async processResponse (resource: URL | Multiaddr[], opts: MiddlewareOptions, response: Response): Promise { + const credentials = opts.credentials ?? 'same-origin' + + if (credentials === 'omit') { + removeSetCookie(response) + return + } + + const origin = opts.headers.get('origin') + + if (origin == null || origin === 'null') { + return + } + + const url = toURL(resource, opts.headers) + for (const value of response.headers.getSetCookie()) { + const cookies = [ + ...(this.cookies.get(url.hostname) ?? []), + ...toCookies(cookie.parse(value)) + ] + + this.cookies.set(url.hostname, cookies) + } + + removeSetCookie(response) + } +} + +/** + * the fetch spec requires not exposing set-cookie to client code + */ +function removeSetCookie (response: Response): Response { + if (response.headers.has('set-cookie')) { + response.headers.delete('set-cookie') + } + + return response +} + +function toCookies (parsed: Record): Cookie[] { + const metadata: Omit = {} + const output: Cookie[] = [] + + Object.entries(parsed).forEach(([name, value]) => { + if (name.toLowerCase() === 'domain' && value != null) { + metadata.domain = value + } + + if (name.toLowerCase() === 'max-age' && value != null) { + metadata.expires = Date.now() + (parseInt(value, 10) * 1000) + } + + if (!COOKIE_FIELDS.includes(name.toLowerCase()) && value != null) { + output.push({ + name, + value + }) + } + }) + + return output.map(c => ({ + ...c, + ...metadata + })) +} + +const COOKIE_FIELDS = [ + 'domain', + 'expires', + 'httponly', + 'max-age', + 'partitioned', + 'path', + 'samesite', + 'secure' +] diff --git a/packages/http/src/middleware/index.ts b/packages/http/src/middleware/index.ts new file mode 100644 index 0000000..3c82d7a --- /dev/null +++ b/packages/http/src/middleware/index.ts @@ -0,0 +1,2 @@ +export * from './cookies.js' +export * from './peer-id-auth.js' diff --git a/packages/http/src/middleware/origin.ts b/packages/http/src/middleware/origin.ts new file mode 100644 index 0000000..e55b727 --- /dev/null +++ b/packages/http/src/middleware/origin.ts @@ -0,0 +1,19 @@ +import { toURL } from '@libp2p/http-utils' +import type { Middleware, MiddlewareOptions } from '@libp2p/http-utils' +import type { Multiaddr } from '@multiformats/multiaddr' + +export class Origin implements Middleware { + async prepareRequest (resource: URL | Multiaddr[], opts: MiddlewareOptions): Promise { + if (opts.headers.get('origin') != null) { + return + } + + if (opts.mode === 'no-cors') { + return + } + + const url = toURL(resource, opts.headers) + + opts.headers.set('origin', `${url.protocol}//${url.host}`) + } +} diff --git a/packages/http/src/middleware/peer-id-auth.ts b/packages/http/src/middleware/peer-id-auth.ts new file mode 100644 index 0000000..4646525 --- /dev/null +++ b/packages/http/src/middleware/peer-id-auth.ts @@ -0,0 +1,193 @@ +import { MissingAuthHeaderError, DEFAULT_AUTH_TOKEN_TTL, ClientInitiatedHandshake } from '@libp2p/http-peer-id-auth' +import { getHost, isWebSocketUpgrade } from '@libp2p/http-utils' +import { InvalidMessageError, InvalidParametersError } from '@libp2p/interface' +import type { Middleware, MiddlewareOptions, HTTP } from '../index.js' +import type { VerifyPeer } from '@libp2p/http-peer-id-auth' +import type { ComponentLogger, PeerId, PrivateKey } from '@libp2p/interface' +import type { Multiaddr } from '@multiformats/multiaddr' + +interface AuthToken { + /** + * The PeerId of the server + */ + peerId: PeerId + + /** + * When the token expires + */ + expires: number + + /** + * The authorization header to send + */ + authorization: string + + /** + * The handshake + */ + handshake: ClientInitiatedHandshake +} + +interface PeerIdAuthComponents { + privateKey: PrivateKey + logger: ComponentLogger + http: HTTP +} + +export const SEC_WEBSOCKET_PROTOCOL_PREFIX = 'authorization=' + +export interface PeerIdAuthInit { + verifyPeer?: VerifyPeer + tokenTTL?: number +} + +export class PeerIdAuth implements Middleware { + private readonly components: PeerIdAuthComponents + private readonly tokens: Map + private readonly tokenTTL: number + private readonly verifyPeer?: VerifyPeer + + constructor (components: PeerIdAuthComponents, init: PeerIdAuthInit) { + this.components = components + this.tokens = new Map() + this.tokenTTL = init.tokenTTL ?? DEFAULT_AUTH_TOKEN_TTL + this.verifyPeer = init.verifyPeer + } + + async prepareRequest (resource: URL | Multiaddr[], opts: MiddlewareOptions): Promise { + const authorization = await this.getOrCreateAuthToken(resource, opts) + + if (isWebSocketInit(opts)) { + opts.protocols = [ + ...(opts.protocols ?? []), + `${SEC_WEBSOCKET_PROTOCOL_PREFIX}${btoa(authorization)}` + ] + } else { + if (opts.headers.get('authorization') != null) { + throw new InvalidParametersError('Will not overwrite existing Authorization header') + } + + opts.headers.set('Authorization', authorization) + } + } + + async getOrCreateAuthToken (resource: URL | Multiaddr[], opts: MiddlewareOptions): Promise { + const key = getCacheKey(resource, opts.headers) + let token = this.tokens.get(key) + + // check token expiry + if (token?.expires != null && token?.expires < Date.now()) { + this.tokens.delete(key) + token = undefined + } + + // create new token + if (token == null) { + return this.createAuthToken(resource, opts) + } + + return token?.authorization + } + + async createAuthToken (resource: URL | Multiaddr[], opts: MiddlewareOptions): Promise { + const hostname = getHost(resource, opts.headers) + const handshake = new ClientInitiatedHandshake(this.components.privateKey, hostname, this.verifyPeer) + const challenge = handshake.getChallenge() + + // copy existing headers + const challengeHeaders = new Headers(opts.headers) + challengeHeaders.set('authorization', challenge) + + // remove any WebSocket upgrade headers + challengeHeaders.delete('connection') + challengeHeaders.delete('upgrade') + + // get the server's response + const resp = await this.components.http.fetch(resource, { + method: 'OPTIONS', + headers: challengeHeaders, + signal: opts.signal, + middleware: opts.middleware + .filter(m => m !== this) + .map(m => () => m) + }) + + // verify the server's challenge + const response = resp.headers.get('www-authenticate') + + if (response == null) { + throw new MissingAuthHeaderError('No www-authenticate header in response') + } + + // verify remote server and answer the server challenge + const authorization = await handshake.verifyServer(response, opts) + + if (handshake.serverId == null) { + throw new InvalidMessageError('Failed to get server PeerId') + } + + const key = getCacheKey(resource, opts.headers) + this.tokens.set(key, { + peerId: handshake.serverId, + authorization, + expires: Date.now() + this.tokenTTL, + handshake + }) + + return authorization + } + + processResponse (resource: URL | Multiaddr[], opts: MiddlewareOptions, response: Response): void { + const key = getCacheKey(resource, opts.headers) + const token = this.tokens.get(key) + + // add the remote peer id as a response header + if (token?.peerId != null) { + const headers = new Headers(response.headers) + headers.set('x-libp2p-peer-id', token.peerId.toString()) + + // the headers property is read-only so we can't just re-assign it + response = new Response(response.body, { + status: response.status, + headers + }) + } + + // store the bearer token if the server provided it + const serverAuthHeader = response.headers.get('authentication-info') + + if (serverAuthHeader != null && token != null) { + token.authorization = token.handshake.decodeBearerToken(serverAuthHeader) + } + } +} + +export function peerIdAuth (init: PeerIdAuthInit = {}): (component: any) => Middleware { + return (components) => { + return new PeerIdAuth(components, init) + } +} + +function isWebSocketInit (opts?: any): opts is { protocols?: string[] } { + if (opts == null) { + return false + } + + return isWebSocketUpgrade(opts.method, opts.headers) +} + +function getCacheKey (resource: URL | Multiaddr[], headers: Headers): string { + let prefix = '' + + if (Array.isArray(resource)) { + const peer = resource.map(ma => ma.getPeerId()) + .filter(Boolean) + .pop() + + if (peer != null) { + prefix = `${peer}-` + } + } + + return `${prefix}${getHost(resource, headers)}` +} diff --git a/packages/http/src/registrar.ts b/packages/http/src/registrar.ts new file mode 100644 index 0000000..b1e10ef --- /dev/null +++ b/packages/http/src/registrar.ts @@ -0,0 +1,226 @@ +import { NOT_FOUND_RESPONSE, normalizeMethod, normalizeUrl, readHeaders, responseToStream, streamToRequest } from '@libp2p/http-utils' +import { CLOSE_MESSAGES } from '@libp2p/http-websocket' +import { InvalidParametersError } from '@libp2p/interface' +import { HTTP_PROTOCOL, WEBSOCKET_HANDLER } from './constants.js' +import { initializeRoute } from './routes/utils.js' +import { wellKnownRoute } from './routes/well-known.js' +import type { WebServer, HTTPRequestHandler, ProtocolMap, WebSocketHandler, HTTPRoute, HandlerRoute } from './index.js' +import type { ComponentLogger, IncomingStreamData, Logger } from '@libp2p/interface' +import type { Registrar } from '@libp2p/interface-internal' + +export interface HTTPRegistrarComponents { + logger: ComponentLogger + registrar: Registrar +} + +export interface HTTPRegistrarInit { + server?: WebServer +} + +interface ProtocolHandler { + protocol: string + route: Required> +} + +export class HTTPRegistrar { + private readonly log: Logger + private readonly components: HTTPRegistrarComponents + private protocols: ProtocolHandler[] + private readonly endpoint?: WebServer + + constructor (components: HTTPRegistrarComponents, init: HTTPRegistrarInit = {}) { + this.components = components + this.log = components.logger.forComponent('libp2p:http:registrar') + this.protocols = [] + this.onStream = this.onStream.bind(this) + this.endpoint = init.server + this.handle('', wellKnownRoute(this)) + } + + async start (): Promise { + await this.components.registrar.handle(HTTP_PROTOCOL, (data) => { + this.onStream(data) + .catch(err => { + this.log.error('could not handle incoming stream - %e', err) + }) + }) + } + + async stop (): Promise { + await this.components.registrar.unhandle(HTTP_PROTOCOL) + } + + private async onStream ({ stream, connection }: IncomingStreamData): Promise { + const info = await readHeaders(stream) + + if (this.canHandle(info)) { + this.log('handling incoming request %s %s', info.method, info.url) + const res = await this.onRequest(streamToRequest(info, stream)) + await responseToStream(res, stream) + await stream.close() + + return + } + + // pass request to endpoint if available + if (this.endpoint == null) { + this.log('cannot handle incoming request %s %s and no endpoint configured', info.method, info.url) + await stream.sink([NOT_FOUND_RESPONSE]) + return + } + + this.log('passing incoming request %s %s to endpoint', info.method, info.url) + this.endpoint.inject(info, stream, connection) + .catch(err => { + this.log.error('error injecting request to endpoint - %e', err) + stream.abort(err) + }) + } + + canHandle (req: { url?: string }): boolean { + const url = normalizeUrl(req).pathname + + if (this.protocols.find(p => p.route.path === url) != null) { + this.log.trace('can handle %s', url) + return true + } + + this.log.trace('cannot handle %s', url) + return false + } + + async onRequest (request: Request): Promise { + this.log('incoming request %s %s', request.method, request.url) + + const handler = this.findHandler(request.url) + + if (handler == null) { + return new Response(null, { + status: 404 + }) + } + + let response: Response + + // support OPTIONS method where endpoint does not + if (!handler.route.method.includes(request.method)) { + if (request.method === 'OPTIONS') { + response = new Response(null, { + status: 204 + }) + } else { + response = new Response(null, { + status: 405 + }) + } + } else { + response = await handler.route.handler(request) + } + + addHeaders(response, request, handler) + + this.log('%s %s %d %s', request.method, request.url, response.status, response.statusText) + + return response + } + + onWebSocket (ws: WebSocket): void { + const handler = this.findHandler(ws.url) + + if (handler != null) { + // @ts-expect-error hidden field + const wsHandler: WebSocketHandler = handler.route[WEBSOCKET_HANDLER] + + if (wsHandler != null) { + wsHandler(ws) + return + } + } + + ws.close(CLOSE_MESSAGES.NORMAL_CLOSURE) + } + + private findHandler (url: string): ProtocolHandler | undefined { + const pathname = url.startsWith('/') ? url : new URL(url).pathname + + this.log('search for handler on path %s', pathname) + + const handler = this.protocols.find(p => p.route.path === pathname) + + if (handler != null) { + this.log('found handler for HTTP protocol %s on path %s', handler.protocol, url) + } + + return handler + } + + handle (protocol: string, route: HTTPRoute): void { + route.path = route.path ?? protocol + + if (this.protocols.find(p => p.protocol === protocol) != null) { + throw new InvalidParametersError(`HTTP protocol handler for ${protocol} already registered`) + } + + if (route.path === '' || !route.path.startsWith('/')) { + route.path = `/${route.path}` + } + + route.cors = route.cors ?? true + route.method = normalizeMethod(route.method) + route = initializeRoute(route, this.components) + + // add handler + this.protocols.push({ + protocol, + // @ts-expect-error optional fields are filled out above + route + }) + + // sort by path length desc so the most specific handler is invoked first + this.protocols.sort(({ route: { path: a } }, { route: { path: b } }) => b.length - a.length) + } + + unhandle (protocol: string): void { + this.protocols = this.protocols.filter(p => p.protocol === protocol) + } + + getProtocolMap (): ProtocolMap { + const output: ProtocolMap = {} + + for (const p of this.protocols) { + if (p.protocol === '') { + continue + } + + output[p.protocol] = { + path: p.route.path + } + } + + return output + } +} + +function addHeaders (response: Response, request: Request, handler: ProtocolHandler): void { + const allow = [...new Set(['OPTIONS', ...handler.route.method])].join(', ') + + if (handler.route.cors) { + if (request.headers.get('Access-Control-Request-Method') != null) { + response.headers.set('access-control-allow-methods', allow) + } + + if (request.headers.get('Access-Control-Request-Headers') != null) { + response.headers.set('access-control-allow-headers', request.headers.get('Access-Control-Request-Headers') ?? '') + } + + if (request.headers.get('Origin') != null) { + response.headers.set('access-control-allow-origin', request.headers.get('Origin') ?? '') + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Access-Control-Allow-Origin#cors_and_caching + response.headers.set('vary', 'Origin') + } + } + + if (request.method === 'OPTIONS') { + response.headers.set('allow', allow) + } +} diff --git a/packages/http/src/routes/index.ts b/packages/http/src/routes/index.ts new file mode 100644 index 0000000..0a30ae2 --- /dev/null +++ b/packages/http/src/routes/index.ts @@ -0,0 +1,2 @@ +export * from './peer-id-auth.js' +export * from './websocket.js' diff --git a/packages/http/src/routes/peer-id-auth.ts b/packages/http/src/routes/peer-id-auth.ts new file mode 100644 index 0000000..c9e01d2 --- /dev/null +++ b/packages/http/src/routes/peer-id-auth.ts @@ -0,0 +1,462 @@ +import { createServerChallenge, serverResponds } from '@libp2p/http-peer-id-auth' +import { normalizeMethod } from '@libp2p/http-utils' +import { WEBSOCKET_HANDLER } from '../constants.js' +import { initializeRoute } from './utils.js' +import { webSocketRoute } from './websocket.js' +import type { HTTPRoute, HandlerRoute } from '../index.js' +import type { ComponentLogger, Logger, PeerId, PrivateKey } from '@libp2p/interface' + +export const DEFAULT_AUTH_TOKEN_TTL = 60 * 60 * 1000 // 1 hour + +interface PeerIdAuthComponents { + privateKey: PrivateKey + logger: ComponentLogger +} + +interface AuthenticationResult { + status: number + headers?: Headers + peer?: PeerId | undefined +} + +interface PeerIdAuthInit { + tokenTTL?: number + verifyHostname?(hostname: string): boolean | Promise + + /** + * If true, and the client has not initiated the HTTP PeerId Auth handshake, + * have the server do it. + */ + requireAuth?: boolean +} + +export class PeerIdAuth { + private readonly components: PeerIdAuthComponents + public readonly log: Logger + private readonly tokenTTL: number + private readonly verifyHostname: (hostname: string) => boolean | Promise + private readonly requireAuth: boolean + + constructor (components: PeerIdAuthComponents, init: PeerIdAuthInit) { + this.components = components + this.log = components.logger.forComponent('libp2p:http:server-peer-id-auth') + this.tokenTTL = init.tokenTTL ?? DEFAULT_AUTH_TOKEN_TTL + this.requireAuth = init.requireAuth ?? false + this.verifyHostname = init.verifyHostname ?? (() => true) + } + + public async authenticateRequest (hostname: string, authHeader?: string | null): Promise { + if (!(await this.verifyHostname(hostname))) { + this.log.error('hostname verification failed') + return { status: 400 } + } + + if (authHeader == null || authHeader === '') { + if (this.requireAuth) { + return this.returnChallenge(hostname) + } + + return { status: 200 } + } + + try { + const result = await serverResponds(authHeader, hostname, this.components.privateKey, this.tokenTTL) + const headers = new Headers() + + let status = 200 + + if (result.info != null) { + headers.set('authentication-info', result.info) + headers.set('access-control-expose-headers', 'authentication-info') + } + + if (result.authenticate != null) { + status = 401 + headers.set('www-authenticate', result.authenticate) + headers.set('access-control-expose-headers', 'www-authenticate') + } + + return { + status, + headers, + peer: result.peerId + } + } catch (err: any) { + this.log.error('failed to respond to client challenge - %e', err) + + if (err.name === 'InvalidMessageError') { + return { status: 400 } + } + + if (err.name === 'NotAuthenticatedError') { + return this.returnChallenge(hostname) + } + + throw err + } + } + + private async returnChallenge (hostname: string): Promise { + return { + status: 401, + headers: new Headers({ + 'www-authenticate': await createServerChallenge(hostname, this.components.privateKey), + 'access-control-expose-headers': 'www-authenticate' + }) + } + } +} + +export interface AuthenticationOptions { + /** + * How long in ms an auth token for a server will be valid for, defaults to + * one hour + * + * @default 360_000 + */ + tokenTTL?: number + + /** + * An optional function that can be used to verify that the hostname of the + * incoming request is valid and supported + */ + verifyHostname?(hostname: string): boolean | Promise + + /** + * If true the request will be rejected if the client does not supply an + * `Authorization` header, pass `false` here to attempt to verify the client + * but allow the request to proceed if it fails + * + * @default true + */ + requireAuth?: boolean +} + +export interface OptionalAuthenticationOptions extends AuthenticationOptions { + /** + * If true the request will be rejected if the client does not supply an + * `Authorization` header, pass `false` here to attempt to verify the client + * but allow the request to proceed if it fails + * + * @default true + */ + requireAuth: false +} + +export interface AuthenticatedWebSocketOptions extends AuthenticationOptions { + /** + * If the request was not a WebSocket request, invoke this method + */ + fallback?: AuthenticatedHTTPRequestHandler + + /** + * The maximum message size to be sent or received over the socket in bytes + * + * @default 10_485_760 + */ + maxMessageSize?: number +} + +export interface OptionallyAuthenticatedWebSocketOptions extends OptionalAuthenticationOptions { + /** + * If the request was not a WebSocket request, invoke this method + */ + fallback?: OptionallyAuthenticatedHTTPRequestHandler + + /** + * The maximum message size to be sent or received over the socket in bytes + * + * @default 10_485_760 + */ + maxMessageSize?: number +} + +/** + * An HTTP handler that accepts the PeerId of the client as an argument + */ +export interface AuthenticatedHTTPRequestHandler { + (req: Request, peerId: PeerId): Promise +} + +/** + * An HTTP handler that accepts the PeerId of the client as an argument, if they + * provided a valid Authorization header + */ +export interface OptionallyAuthenticatedHTTPRequestHandler { + (req: Request, peerId?: PeerId): Promise +} + +/** + * An WebSocket handler that accepts the PeerId of the client as an argument + */ +export interface AuthenticatedWebSocketHandler { + (socket: WebSocket, peerId: PeerId): void +} + +/** + * An WebSocket handler that accepts the PeerId of the client as an argument, if + * they provided a valid Authorization header + */ +export interface OptionallyAuthenticatedWebSocketHandler { + (socket: WebSocket, peerId?: PeerId): void +} + +function isOptionalAuth (obj: any): obj is OptionallyAuthenticatedHandler { + return obj.requireAuth === false +} + +async function authenticate (req: Request, authResult: AuthenticationResult, handlerMethods: string[], next: AuthenticatedHandler): Promise +async function authenticate (req: Request, authResult: AuthenticationResult, handlerMethods: string[], next: OptionallyAuthenticatedHandler): Promise +async function authenticate (req: Request, authResult: AuthenticationResult, handlerMethods: string[], next: AuthenticatedHandler | OptionallyAuthenticatedHandler): Promise { + const authIsOptional = isOptionalAuth(next) + + if (!authIsOptional && (authResult.peer == null || authResult.status !== 200)) { + return new Response(undefined, { + status: authResult.status, + headers: authResult.headers + }) + } + + if (!handlerMethods.includes(req.method)) { + // handle auth requests + let res: Response + + if (req.method === 'OPTIONS') { + // support OPTIONS if the handler doesn't + res = new Response(undefined, { + status: 204, + headers: authResult.headers + }) + } else { + // unsupported method + res = new Response(undefined, { + status: 405 + }) + } + + // add auth headers to response + if (authResult.headers !== undefined) { + for (const [key, value] of authResult.headers) { + res.headers.set(key, value) + } + } + + return res + } + + // @ts-expect-error cannot derive handler type + return next.handler(req, authResult.peer) +} + +type OptionallyAuthenticatedHandler = HandlerRoute & OptionalAuthenticationOptions +type AuthenticatedHandler = HandlerRoute & AuthenticationOptions + +type OptionallyAuthenticatedEndpoint = HTTPRoute & OptionalAuthenticationOptions +type AuthenticatedEndpoint = HTTPRoute & AuthenticationOptions + +/** + * Attempt to authenticate the client before request processing to discover + * their PeerID. + * + * If the `requireAuth` option is false, no authentication will be attempted + * unless the client initiates it. + * + * If it is `true` or `undefined`, the server will initiate the authentication + * handshake if the client has not done so. + * + * @see https://github.com/libp2p/specs/blob/master/http/peer-id-auth.md + */ +export function authenticatedRoute (handler: OptionallyAuthenticatedEndpoint): HTTPRoute +export function authenticatedRoute (handler: AuthenticatedEndpoint): HTTPRoute +export function authenticatedRoute (handler: OptionallyAuthenticatedEndpoint | AuthenticatedEndpoint): HTTPRoute { + const handlerMethods: string[] = normalizeMethod(handler.method) + + return { + path: handler.path, + method: ['OPTIONS', ...handlerMethods], + cors: handler.cors, + init: (components: PeerIdAuthComponents) => { + const auth = new PeerIdAuth(components, handler) + const next = initializeRoute(handler, components) + + return async (req: Request): Promise => { + const authResult = await auth.authenticateRequest(readHostname(req), req.headers.get('Authorization')) + + return authenticate(req, authResult, handlerMethods, next) + } + } + } +} + +type OptionallyAuthenticatedWebSocketEndpoint = HTTPRoute & OptionallyAuthenticatedWebSocketOptions +type AuthenticatedWebSocketEndpoint = HTTPRoute & AuthenticatedWebSocketOptions + +/** + * Attempt to authenticate the client before request processing to discover + * their PeerID. + * + * The authorization token should be passed as a protocol prefixed with + * `authorization=`. + * + * To allow use of actual protocol field, multiple values should be + * comma-delimited, e.g. `authorization=foo,actual,useful,protocols` + * + * @see https://github.com/libp2p/specs/blob/master/http/peer-id-auth.md + */ +export function authenticatedWebSocketRoute (handler: OptionallyAuthenticatedWebSocketEndpoint): HTTPRoute +export function authenticatedWebSocketRoute (handler: AuthenticatedWebSocketEndpoint): HTTPRoute +export function authenticatedWebSocketRoute (handler: OptionallyAuthenticatedWebSocketEndpoint | AuthenticatedWebSocketEndpoint): HTTPRoute { + const handlerMethods: string[] = normalizeMethod(handler.method) + + const output: HTTPRoute = { + path: handler.path, + method: ['OPTIONS', ...handlerMethods], + cors: handler.cors, + init: (components: PeerIdAuthComponents) => { + const auth = new PeerIdAuth(components, handler) + const next: any = initializeRoute(handler, components) + + // allow invoking the handler with a pre-upgraded socket + output[WEBSOCKET_HANDLER] = (ws) => { + // need to read the authorization header from the websocket protocol + + // TODO: we should have a way of doing this before the websocket upgrade + // has been negotiated + auth.authenticateRequest(readHostname(ws), readProtocol(ws)) + .then(authResult => { + next.handler(ws, authResult.peer) + }) + .catch(() => { + ws.close() + }) + } + + return async (req: Request): Promise => { + const authResult = await auth.authenticateRequest(readHostname(req), readAuthorization(req) ?? readSecWebSocketProtocol(req)) + + return authenticate(req, authResult, handlerMethods, { + ...next, + handler: async (req, peerId) => { + const wsRoute = initializeRoute(webSocketRoute({ + ...next, + handler: (ws) => { + next.handler(ws, peerId) + }, + fallback: next.fallback == null + ? undefined + : async (req: Request): Promise => { + return authenticate(req, authResult, handlerMethods, { + ...next, + handler: async (res, peerId) => { + if (next.fallback == null) { + // should not get here because we have already + // null-guarded on `handler.fallback` + return new Response(undefined, { + status: 500 + }) + } + + return next.fallback(res, peerId) + } + }) + } + }), components) + + return wsRoute.handler(req) + } + }) + } + } + } + + return output +} + +function readHostname (req: { url: string }): string { + const url = new URL(req.url) + let hostname = url.hostname + + if (url.port === '' || url.port === undefined) { + return hostname + } + + if (url.protocol === 'http:' && url.port !== '80') { + hostname += ':' + url.port + } + + if (url.protocol === 'https:' && url.port !== '443') { + hostname += ':' + url.port + } + + if (hostname === '') { + throw new Error('No hostname') + } + + return hostname +} + +function readAuthorization (req: Request): string | undefined { + const authorization = req.headers.get('Authorization') + + if (authorization == null) { + return + } + + return authorization +} + +export const SEC_WEBSOCKET_PROTOCOL_PREFIX = 'authorization=' + +function readSecWebSocketProtocol (req: Request): string | undefined { + const protocol = req.headers.get('Sec-WebSocket-Protocol') + + if (protocol == null) { + return + } + + const protos = protocol.split(',') + + const authorization = protos + .filter(p => p.startsWith(SEC_WEBSOCKET_PROTOCOL_PREFIX)) + .pop() + + // remove authorization field from protocol if present + if (authorization != null) { + req.headers.set('Sec-WebSocket-Protocol', protos + .filter(p => !p.startsWith(SEC_WEBSOCKET_PROTOCOL_PREFIX)) + .join(',')) + } + + if (authorization == null) { + return + } + + return atob(authorization.substring(SEC_WEBSOCKET_PROTOCOL_PREFIX.length)) +} + +function readProtocol (ws: { protocol?: string }): string | undefined { + const protocol = ws.protocol + + if (protocol == null) { + return + } + + const protos = protocol.split(',') + + const authorization = protos + .filter(p => p.startsWith(SEC_WEBSOCKET_PROTOCOL_PREFIX)) + .pop() + + // remove authorization field from protocol if present + if (authorization != null) { + ws.protocol = protos + .filter(p => !p.startsWith(SEC_WEBSOCKET_PROTOCOL_PREFIX)) + .join(',') + } + + if (authorization == null) { + return + } + + return atob(authorization.substring(SEC_WEBSOCKET_PROTOCOL_PREFIX.length)) +} diff --git a/packages/http/src/routes/utils.ts b/packages/http/src/routes/utils.ts new file mode 100644 index 0000000..0438753 --- /dev/null +++ b/packages/http/src/routes/utils.ts @@ -0,0 +1,28 @@ +import type { HTTPRoute, HandlerRoute, ServiceRoute } from '../index.js' + +/** + * Returns true if the passed route requires initialization + */ +function isInitializable , S extends ServiceRoute> (obj: H | S): obj is S { + // @ts-expect-error init is not a property of H + return typeof obj.init === 'function' +} + +/** + * Initializes a `ServiceRoute` and converts it to a `HandlerRoute`. + * + * If the passed route has an `init` method, it invokes it and sets the + * `handler` field on the endpoint with the return value, then deletes the + * `init` property, otherwise it returns the endpoint unaltered. + */ +export function initializeRoute (serviceOrHandler: HTTPRoute, components: any): HandlerRoute { + if (isInitializable(serviceOrHandler)) { + const route: any = serviceOrHandler + route.handler = serviceOrHandler.init(components) + delete route.init + + return route + } + + return serviceOrHandler +} diff --git a/packages/http/src/routes/websocket.ts b/packages/http/src/routes/websocket.ts new file mode 100644 index 0000000..d4ce366 --- /dev/null +++ b/packages/http/src/routes/websocket.ts @@ -0,0 +1,79 @@ +import { Response, isWebSocketUpgrade, normalizeMethod, getServerUpgradeHeaders } from '@libp2p/http-utils' +import { RequestWebSocket } from '@libp2p/http-websocket' +import { InvalidParametersError } from '@libp2p/interface' +import { WEBSOCKET_HANDLER } from '../constants.js' +import { initializeRoute } from './utils.js' +import type { HTTPRoute, RouteOptions, HTTPRequestHandler, WebSocketHandler } from '../index.js' + +export interface WebSocketRouteOptions extends RouteOptions { + /** + * If the request does not have a `Connection: upgrade` header, pass a + * fallback here to handle the request normally, otherwise the request + * will be rejected with a 400 error. + */ + fallback?: HTTPRequestHandler + + /** + * The maximum message size to be sent or received over the socket in bytes + * + * @default 10_485_760 + */ + maxMessageSize?: number +} + +export type WebSocketRoute = HTTPRoute & WebSocketRouteOptions + +/** + * Negotiate a connection upgrade to the WebSocket protocol and call the passed + * handler + */ +export function webSocketRoute (route: WebSocketRoute): HTTPRoute { + const method = normalizeMethod(route.method, ['GET']) + + if (route.fallback == null && method.filter(method => method !== 'GET').length > 0) { + throw new InvalidParametersError('WebSocket handlers only support the GET HTTP method') + } + + const output: HTTPRoute = { + ...route, + init: (components) => { + const next = initializeRoute(route, components) + + // allow invoking the handler with a pre-upgraded socket + output[WEBSOCKET_HANDLER] = next.handler + + return async (req: Request): Promise => { + // check upgrade has been requested + if (!isWebSocketUpgrade(req.method, req.headers)) { + if (route?.fallback != null) { + return route.fallback(req) + } + + return new Response(null, { + status: 400 + }) + } + + const transform = new TransformStream() + + try { + const res = new Response(transform.readable, { + status: 101, + headers: await getServerUpgradeHeaders(req.headers) + }) + + const ws = new RequestWebSocket(req, transform.writable, route) + next.handler(ws) + + return res + } catch (err) { + return new Response(null, { + status: 500 + }) + } + } + } + } + + return output +} diff --git a/packages/http/src/routes/well-known.ts b/packages/http/src/routes/well-known.ts new file mode 100644 index 0000000..df83f28 --- /dev/null +++ b/packages/http/src/routes/well-known.ts @@ -0,0 +1,27 @@ +import { webSocketRoute } from './websocket.js' +import type { HTTPRoute } from '../index.js' +import type { HTTPRegistrar } from '../registrar.js' + +export const WELL_KNOWN_PROTOCOLS_PATH = '/.well-known/libp2p/protocols' + +export function wellKnownRoute (registrar: HTTPRegistrar): HTTPRoute { + return webSocketRoute({ + path: WELL_KNOWN_PROTOCOLS_PATH, + method: ['GET'], + cors: true, + handler: ws => { + const map = JSON.stringify(registrar.getProtocolMap()) + ws.send(map) + ws.close() + }, + fallback: async (req) => { + const map = JSON.stringify(registrar.getProtocolMap()) + return new Response(map, { + headers: { + 'Content-Type': 'application/json', + 'Content-Length': `${map.length}` + } + }) + } + }) +} diff --git a/packages/http/src/utils.ts b/packages/http/src/utils.ts new file mode 100644 index 0000000..ac3ceaa --- /dev/null +++ b/packages/http/src/utils.ts @@ -0,0 +1,26 @@ +import type { MiddlewareOptions } from './index.js' +import type { Multiaddr } from '@multiformats/multiaddr' + +export async function prepareAndSendRequest (resource: URL | Multiaddr[], opts: MiddlewareOptions, sendRequest: () => Promise): Promise { + for (const middleware of opts.middleware) { + await middleware.prepareRequest?.(resource, opts) + } + + return sendRequest() +} + +export async function prepareAndConnect (resource: URL | Multiaddr[], opts: MiddlewareOptions, connect: () => Promise): Promise { + for (const middleware of opts.middleware) { + await middleware.prepareRequest?.(resource, opts) + } + + return connect() +} + +export async function processResponse (resource: URL | Multiaddr[], opts: MiddlewareOptions, response: Response): Promise { + for (const middleware of opts.middleware) { + await middleware.processResponse?.(resource, opts, response) + } + + return response +} diff --git a/packages/http/test/index.spec.ts b/packages/http/test/index.spec.ts new file mode 100644 index 0000000..a59c147 --- /dev/null +++ b/packages/http/test/index.spec.ts @@ -0,0 +1,5 @@ +describe('@libp2p/http', () => { + it('should run a test', () => { + + }) +}) diff --git a/packages/http/tsconfig.json b/packages/http/tsconfig.json new file mode 100644 index 0000000..a6681cd --- /dev/null +++ b/packages/http/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ], + "references": [ + { + "path": "../http-fetch" + }, + { + "path": "../http-peer-id-auth" + }, + { + "path": "../http-utils" + }, + { + "path": "../http-websocket" + } + ] +} diff --git a/packages/http/typedoc.json b/packages/http/typedoc.json new file mode 100644 index 0000000..af36672 --- /dev/null +++ b/packages/http/typedoc.json @@ -0,0 +1,8 @@ +{ + "readme": "none", + "entryPoints": [ + "./src/index.ts", + "./src/middleware/index.ts", + "./src/routes/index.ts" + ] +} diff --git a/packages/interop/.aegir.js b/packages/interop/.aegir.js new file mode 100644 index 0000000..03bbd8c --- /dev/null +++ b/packages/interop/.aegir.js @@ -0,0 +1,139 @@ +import { stop } from '@libp2p/interface' +import http from 'node:http' + +function stoppableServer (server) { + return { + start: () => {}, + stop: () => { + server.close() + server.closeAllConnections() + } + } +} + +async function startHTTPServer (server) { + return new Promise((resolve, reject) => { + server.on('listening', () => { + const address = server.address() + + if (address == null || typeof address === 'string') { + reject(new Error('Did not listen on port')) + return + } + + resolve(address.port) + }) + server.on('error', err => { + reject(err) + }) + server.listen(0) + }) +} + +/** @type {import('aegir').PartialOptions} */ +export default { + build: { + bundlesizeMax: '24kB' + }, + test: { + before: async () => { + const { createServer, canHandle } = await import('@libp2p/http-server/node') + const { nodeServer } = await import('@libp2p/http-server') + const { getHTTPOverLibp2pHandler } = await import('./dist/test/fixtures/get-libp2p.js') + const { createHttp } = await import('./dist/test/fixtures/create-http.js') + const { createFastifyHTTP } = await import('./dist/test/fixtures/create-fastify-http.js') + const { createExpress } = await import('./dist/test/fixtures/create-express.js') + const { createWss } = await import('./dist/test/fixtures/create-wss.js') + const { createFastifyWebSocket } = await import('./dist/test/fixtures/create-fastify-websocket.js') + const { getLibp2pOverHttpHandler } = await import('./dist/test/fixtures/get-libp2p.js') + + // --- http-over-libp2p + // these are libp2p nodes that we pass an HTTP server to - eg. in the + // tests we open a libp2p stream to these nodes and send an HTTP request, + // the node hands the request off to the HTTP server for processing + const jsHttpListener = await getHTTPOverLibp2pHandler(nodeServer(createHttp(createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const nodeHttpListener = await getHTTPOverLibp2pHandler(nodeServer(createHttp(http.createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const jsExpressListener = await getHTTPOverLibp2pHandler(nodeServer(createExpress(createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const nodeHttpExpressListener = await getHTTPOverLibp2pHandler(nodeServer(createExpress(http.createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const jsFastifyListener = await getHTTPOverLibp2pHandler(nodeServer(await createFastifyHTTP(createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const nodeHttpFastifyListener = await getHTTPOverLibp2pHandler(nodeServer(await createFastifyHTTP(http.createServer())), '/ip4/0.0.0.0/tcp/0/ws') + + // --- ws-over-libp2p + // as above but with WebSocket servers instead of HTTP + const jsWssListener = await getHTTPOverLibp2pHandler(nodeServer(createWss(createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const nodeHttpWssListener = await getHTTPOverLibp2pHandler(nodeServer(createWss(http.createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const jsFastifyWsListener = await getHTTPOverLibp2pHandler(nodeServer(await createFastifyWebSocket(createServer())), '/ip4/0.0.0.0/tcp/0/ws') + const nodeHttpFastifyWsListener = await getHTTPOverLibp2pHandler(nodeServer(await createFastifyWebSocket(http.createServer())), '/ip4/0.0.0.0/tcp/0/ws') + + // --- libp2p-over-http + // these are HTTP servers that accept HTTP requests and can hand them off + // to libp2p for processing + const libp2pOverHttpHandler = await getLibp2pOverHttpHandler() + const express = createExpress(http.createServer(), canHandle(libp2pOverHttpHandler)) + const nodeHttp = createHttp(http.createServer(), canHandle(libp2pOverHttpHandler)) + const fastify = await createFastifyHTTP(http.createServer(), canHandle(libp2pOverHttpHandler)) + + // --- libp2p-over-ws + // as above but with WebSocket servers instead of HTTP + const wss = createWss(http.createServer(), canHandle(libp2pOverHttpHandler)) + const fastifyWs = await createFastifyWebSocket(http.createServer(), canHandle(libp2pOverHttpHandler)) + + return { + // http-over-libp2p + jsHttpListener, + nodeHttpListener, + jsExpressListener, + nodeHttpExpressListener, + jsFastifyListener, + nodeHttpFastifyListener, + + // ws-over-libp2p + jsWssListener, + nodeHttpWssListener, + jsFastifyWsListener, + nodeHttpFastifyWsListener, + + // libp2p-over-http + libp2pOverHttpHandler, + nodeHttp: stoppableServer(nodeHttp), + express: stoppableServer(express), + fastify: stoppableServer(fastify), + + // libp2p-over-ws + wss: stoppableServer(wss), + fastifyWs: stoppableServer(fastifyWs), + + env: { + // http-over-libp2p + LIBP2P_JS_HTTP_MULTIADDR: jsHttpListener.getMultiaddrs()[0], + LIBP2P_NODE_HTTP_MULTIADDR: nodeHttpListener.getMultiaddrs()[0], + LIBP2P_JS_EXPRESS_MULTIADDR: jsExpressListener.getMultiaddrs()[0], + LIBP2P_NODE_EXPRESS_MULTIADDR: nodeHttpExpressListener.getMultiaddrs()[0], + LIBP2P_JS_FASTIFY_MULTIADDR: jsFastifyListener.getMultiaddrs()[0], + LIBP2P_NODE_FASTIFY_MULTIADDR: nodeHttpFastifyListener.getMultiaddrs()[0], + + // ws-over-libp2p + LIBP2P_JS_WSS_MULTIADDR: jsWssListener.getMultiaddrs()[0], + LIBP2P_NODE_WSS_MULTIADDR: nodeHttpWssListener.getMultiaddrs()[0], + LIBP2P_JS_FASTIFY_WS_MULTIADDR: jsFastifyWsListener.getMultiaddrs()[0], + LIBP2P_NODE_FASTIFY_WS_MULTIADDR: nodeHttpFastifyWsListener.getMultiaddrs()[0], + + // libp2p-over-http + HTTP_PEER_ID: `${libp2pOverHttpHandler.peerId}`, + HTTP_NODE_HTTP_MULTIADDR: `/ip4/127.0.0.1/tcp/${await startHTTPServer(nodeHttp)}/http`, + HTTP_EXPRESS_MULTIADDR: `/ip4/127.0.0.1/tcp/${await startHTTPServer(express)}/http`, + HTTP_FASTIFY_MULTIADDR: `/ip4/127.0.0.1/tcp/${await startHTTPServer(fastify)}/http`, + + // libp2p-over-ws + WS_WSS_MULTIADDR: `/ip4/127.0.0.1/tcp/${await startHTTPServer(wss)}/http`, + WS_FASTIFY_MULTIADDR: `/ip4/127.0.0.1/tcp/${await startHTTPServer(fastifyWs)}/http` + } + } + }, + after: async (_, before) => { + await stop( + ...Object.values(before) + ) + } + } +} diff --git a/packages/interop/LICENSE b/packages/interop/LICENSE new file mode 100644 index 0000000..20ce483 --- /dev/null +++ b/packages/interop/LICENSE @@ -0,0 +1,4 @@ +This project is dual licensed under MIT and Apache-2.0. + +MIT: https://www.opensource.org/licenses/mit +Apache-2.0: https://www.apache.org/licenses/license-2.0 diff --git a/packages/interop/LICENSE-APACHE b/packages/interop/LICENSE-APACHE new file mode 100644 index 0000000..14478a3 --- /dev/null +++ b/packages/interop/LICENSE-APACHE @@ -0,0 +1,5 @@ +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/packages/interop/LICENSE-MIT b/packages/interop/LICENSE-MIT new file mode 100644 index 0000000..72dc60d --- /dev/null +++ b/packages/interop/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/packages/interop/README.md b/packages/interop/README.md new file mode 100644 index 0000000..b89217c --- /dev/null +++ b/packages/interop/README.md @@ -0,0 +1,42 @@ +# @libp2p/http + +[![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-http.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-http) +[![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-http/js-test-and-release.yml?branch=main\&style=flat-square)](https://github.com/libp2p/js-libp2p-http/actions/workflows/js-test-and-release.yml?query=branch%3Amain) + +> Interop tests for the @libp2p/http collection of modules + +# About + + + +Interop tests for `@libp2p/http`. + +# API Docs + +- + +# License + +Licensed under either of + +- Apache 2.0, ([LICENSE-APACHE](https://github.com/libp2p/js-libp2p-http/LICENSE-APACHE) / ) +- MIT ([LICENSE-MIT](https://github.com/libp2p/js-libp2p-http/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/packages/interop/package.json b/packages/interop/package.json new file mode 100644 index 0000000..f664d35 --- /dev/null +++ b/packages/interop/package.json @@ -0,0 +1,68 @@ +{ + "name": "@libp2p/http-interop", + "version": "0.0.0", + "description": "Interop tests for the @libp2p/http collection of modules", + "license": "Apache-2.0 OR MIT", + "homepage": "https://github.com/libp2p/js-libp2p-http/tree/main/packages/interop#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/libp2p/js-libp2p-http.git" + }, + "bugs": { + "url": "https://github.com/libp2p/js-libp2p-http/issues" + }, + "type": "module", + "scripts": { + "build": "aegir build", + "clean": "aegir clean", + "lint": "aegir lint", + "test": "aegir test", + "test:chrome": "aegir test -t browser --cov", + "test:firefox": "aegir test -t browser --browser firefox --cov", + "test:node": "aegir test -t node --cov", + "test:electron-main": "aegir test -t electron-main", + "test:chrome-webworker": "aegir test -t webworker", + "test:webkit": "aegir test -t browser -- --browser webkit", + "test:firefox-webworker": "aegir test -t webworker -- --browser firefox", + "dep-check": "aegir dep-check" + }, + "devDependencies": { + "@chainsafe/libp2p-noise": "^16.1.3", + "@chainsafe/libp2p-yamux": "^7.0.1", + "@fastify/cookie": "^11.0.2", + "@fastify/websocket": "^11.1.0", + "@libp2p/crypto": "^5.1.4", + "@libp2p/http": "~0.0.0", + "@libp2p/http-ping": "~0.0.0", + "@libp2p/http-server": "~0.0.0", + "@libp2p/interface": "^2.10.2", + "@libp2p/memory": "^1.1.9", + "@libp2p/peer-id": "^5.1.5", + "@libp2p/ping": "^2.0.32", + "@libp2p/websockets": "^9.2.13", + "@multiformats/multiaddr": "^12.4.0", + "@types/cookie-parser": "^1.4.8", + "@types/express": "^5.0.2", + "@types/ws": "^8.18.1", + "aegir": "^47.0.16", + "cookie-parser": "^1.4.7", + "express": "^5.1.0", + "fastify": "^5.3.3", + "libp2p": "^2.8.8", + "p-defer": "^4.0.1", + "p-event": "^6.0.1", + "sinon": "^20.0.0", + "ws": "^8.18.2" + }, + "browser": { + "./dist/src/auth/agent.js": "./dist/src/auth/agent.browser.js", + "./dist/src/http.js": "./dist/src/http.browser.js", + "./dist/src/http/index.js": "./dist/src/http/index.browser.js", + "./dist/test/index.spec.js": "./dist/test/index.browser.spec.js", + "node:stream": "readable-stream", + "node:http": false, + "undici": false + }, + "private": true, + "sideEffects": false +} diff --git a/packages/interop/src/index.ts b/packages/interop/src/index.ts new file mode 100644 index 0000000..336ce12 --- /dev/null +++ b/packages/interop/src/index.ts @@ -0,0 +1 @@ +export {} diff --git a/packages/interop/test/cookies.spec.ts b/packages/interop/test/cookies.spec.ts new file mode 100644 index 0000000..aae88c2 --- /dev/null +++ b/packages/interop/test/cookies.spec.ts @@ -0,0 +1,151 @@ +import { nodeServer } from '@libp2p/http-server' +import { createServer } from '@libp2p/http-server/node' +import { stop } from '@libp2p/interface' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' +import { createHttp } from './fixtures/create-http.js' +import { getClient, getHTTPOverLibp2pHandler } from './fixtures/get-libp2p.js' +import type { HTTP } from '@libp2p/http' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Libp2p } from 'libp2p' + +interface Test { + name: string + startServer(): Promise + stopServer(): Promise +} + +let listener: Libp2p<{ http: HTTP }> + +const tests: Test[] = [{ + name: 'in-process server', + startServer: async () => { + const server = createHttp(createServer()) + listener = await getHTTPOverLibp2pHandler(nodeServer(server)) + + return listener.getMultiaddrs() + }, + stopServer: async () => { + await stop(listener) + } +}, { + name: 'js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_HTTP_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_HTTP_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'express/js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_EXPRESS_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'express/node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_EXPRESS_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'fastify/js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_FASTIFY_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'fastify/node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_FASTIFY_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}] + +for (const test of tests) { + describe(`cookies - ${test.name}`, () => { + let client: Libp2p<{ http: HTTP }> + let listenerMultiaddrs: Multiaddr[] + + beforeEach(async () => { + client = await getClient() + listenerMultiaddrs = await test.startServer() + }) + + afterEach(async () => { + await stop(client) + await test.stopServer() + }) + + it('should support cookies', async () => { + const setResponse = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/set-cookies')), { + headers: { + host: 'test-with-cookies.com' + }, + credentials: 'include' + }) + expect(setResponse.status).to.equal(201) + expect(setResponse.headers.get('set-cookie')).to.not.be.ok() + + const getResponse = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/get-cookies')), { + headers: { + host: 'test-with-cookies.com' + }, + credentials: 'include' + }) + expect(getResponse.status).to.equal(200) + await expect(getResponse.json()).to.eventually.deep.equal([ + 'cookie-1=value-1', + 'cookie-2=value-2' + ]) + }) + + it('should support ignoring cookies', async () => { + const setResponse = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/set-cookies')), { + headers: { + host: 'test-without-cookies.com' + }, + credentials: 'omit' + }) + expect(setResponse.status).to.equal(201) + expect(setResponse.headers.get('set-cookie')).to.not.be.ok() + + const getResponse = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/get-cookies')), { + headers: { + host: 'test-without-cookies.com' + }, + credentials: 'omit' + }) + expect(getResponse.status).to.equal(200) + await expect(getResponse.json()).to.eventually.deep.equal([]) + }) + }) +} diff --git a/packages/interop/test/fetch.spec.ts b/packages/interop/test/fetch.spec.ts new file mode 100644 index 0000000..6ccbb6b --- /dev/null +++ b/packages/interop/test/fetch.spec.ts @@ -0,0 +1,258 @@ +import { nodeServer } from '@libp2p/http-server' +import { createServer } from '@libp2p/http-server/node' +import { stop } from '@libp2p/interface' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' +import { createHttp } from './fixtures/create-http.js' +import { getClient, getHTTPOverLibp2pHandler } from './fixtures/get-libp2p.js' +import type { HTTP } from '@libp2p/http' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Libp2p } from 'libp2p' + +interface Test { + name: string + startServer(): Promise + stopServer(): Promise +} + +let listener: Libp2p<{ http: HTTP }> + +const tests: Test[] = [{ + name: 'in-process server', + startServer: async () => { + const server = createHttp(createServer()) + listener = await getHTTPOverLibp2pHandler(nodeServer(server)) + + return listener.getMultiaddrs() + }, + stopServer: async () => { + await stop(listener) + } +}, { + name: 'js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_HTTP_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_HTTP_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'express/js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_EXPRESS_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'express/node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_EXPRESS_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'fastify/js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_FASTIFY_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'fastify/node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_FASTIFY_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}] + +for (const test of tests) { + describe(`fetch - ${test.name}`, () => { + let client: Libp2p<{ http: HTTP }> + let listenerMultiaddrs: Multiaddr[] + + beforeEach(async () => { + client = await getClient() + listenerMultiaddrs = await test.startServer() + }) + + afterEach(async () => { + await stop(client) + await test.stopServer() + }) + + it('should fetch GET', async () => { + const response = await client.services.http.fetch(listenerMultiaddrs, { + headers: { + host: 'example.com' + } + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal('Hello World!') + }) + + it('should fetch POST with string', async () => { + const body = 'echo body' + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal(body) + }) + + it('should fetch POST with ArrayBuffer', async () => { + const body = Uint8Array.from([0, 1, 2, 3, 4]).buffer + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body + }) + expect(response.status).to.equal(200) + await expect(response.arrayBuffer()).to.eventually.deep.equal(body) + }) + + it('should fetch POST with Blob', async () => { + const body = Uint8Array.from([0, 1, 2, 3, 4]).buffer + const blob = new Blob([body]) + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body: blob + }) + expect(response.status).to.equal(200) + await expect(response.arrayBuffer()).to.eventually.deep.equal(body) + }) + + it('should fetch POST with DataView', async () => { + const body = Uint8Array.from([0, 1, 2, 3, 4]).buffer + const view = new DataView(body) + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body: view + }) + expect(response.status).to.equal(200) + await expect(response.arrayBuffer()).to.eventually.deep.equal(body) + }) + + it('should fetch POST with File', async () => { + const body = Uint8Array.from([0, 1, 2, 3, 4]).buffer + const file = new File([body], 'file.txt') + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body: file + }) + expect(response.status).to.equal(200) + await expect(response.arrayBuffer()).to.eventually.deep.equal(body) + }) + + it('should fetch POST with FormData', async () => { + const data = Uint8Array.from([0, 1, 2, 3, 4]).buffer + const blob = new Blob([data]) + const body = new FormData() + body.append('foo', 'bar') + body.append('baz', blob) + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body + }) + expect(response.status).to.equal(200) + }) + + it('should fetch POST with TypedArray', async () => { + const body = Uint8Array.from([0, 1, 2, 3, 4]) + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body + }) + expect(response.status).to.equal(200) + await expect(response.arrayBuffer()).to.eventually.deep.equal(body.buffer) + }) + + it('should fetch POST with URLSearchParams', async () => { + const body = new URLSearchParams() + body.set('foo', 'bar') + body.set('baz', 'qux') + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.deep.equal(body.toString()) + }) + + it('should fetch POST with ReadableStream', async () => { + const buf = Uint8Array.from([0, 1, 2, 3, 4]) + const body = new ReadableStream({ + start (controller) { + controller.enqueue(buf) + controller.close() + } + }) + + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate('/http-path/echo')), { + method: 'POST', + headers: { + host: 'example.com' + }, + body + }) + expect(response.status).to.equal(200) + await expect(response.arrayBuffer()).to.eventually.deep.equal(buf.buffer) + }) + }) +} diff --git a/packages/interop/test/fixtures/create-express.ts b/packages/interop/test/fixtures/create-express.ts new file mode 100644 index 0000000..a6006a5 --- /dev/null +++ b/packages/interop/test/fixtures/create-express.ts @@ -0,0 +1,51 @@ +import cookieParser from 'cookie-parser' +import express from 'express' +import type { CanHandle } from '@libp2p/http-server/node' +import type { Server } from 'node:http' + +/** + * Creates an Express server that optionally delegates request handling to a + * Libp2p Over HTTP handler + */ +export function createExpress (server: Server, handled?: CanHandle): Server { + const app = express() + app.use(cookieParser()) + app.get('/', (req, res) => { + res.send('Hello World!') + }) + app.post('/echo', (req, res) => { + req.on('data', (buf) => { + res.write(buf) + }) + req.on('end', () => { + res.end() + }) + req.on('error', (err) => { + res.destroy(err) + }) + }) + app.get('/set-cookies', (req, res) => { + res.appendHeader('set-cookie', `cookie-1=value-1; Domain=${req.headers.host}; Max-Age=3600`) + res.appendHeader('set-cookie', 'cookie-2=value-2') + res.writeHead(201) + res.end() + }) + app.get('/get-cookies', (req, res) => { + res.end(JSON.stringify(Object.entries(req.cookies).map(([key, value]) => `${key}=${value}`))) + }) + + server.on('request', (req, res) => { + if (handled?.(req, res) === true) { + return + } + + res.setHeader('Access-Control-Allow-Origin', '*') + res.setHeader('Access-Control-Request-Method', '*') + res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST') + res.setHeader('Access-Control-Allow-Headers', '*') + + app(req, res) + }) + + return server +} diff --git a/packages/interop/test/fixtures/create-fastify-http.ts b/packages/interop/test/fixtures/create-fastify-http.ts new file mode 100644 index 0000000..fbdeaa4 --- /dev/null +++ b/packages/interop/test/fixtures/create-fastify-http.ts @@ -0,0 +1,71 @@ +import cookies from '@fastify/cookie' +import { fastify } from 'fastify' +import type { CanHandle } from '@libp2p/http-server/node' +import type { FastifyRequest } from 'fastify' +import type { Server, IncomingMessage } from 'node:http' + +export async function createFastifyHTTP (server: Server, handled?: CanHandle): Promise { + const app = fastify({ + serverFactory: (app, opts) => { + server.addListener('request', (req, res) => { + if (handled?.(req, res) === true) { + return + } + + res.setHeader('Access-Control-Allow-Origin', '*') + res.setHeader('Access-Control-Request-Method', '*') + res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST') + res.setHeader('Access-Control-Allow-Headers', '*') + + app(req, res) + }) + + return server + } + }) + + await app.register(cookies) + + // fastify only supports 'application/json' and 'text/plain' by default + app.addContentTypeParser('*', async (req: FastifyRequest, payload: IncomingMessage) => { + return payload + }) + app.get('/', async (req, reply) => { + await reply.send('Hello World!') + }) + app.post('/echo', (req, reply) => { + if (typeof req.body === 'string') { + return reply.send(req.body) + } + + req.raw.on('data', (buf) => { + reply.raw.write(buf) + }) + req.raw.on('end', () => { + reply.raw.end() + }) + req.raw.on('error', (err) => { + reply.raw.destroy(err) + }) + }) + app.get('/set-cookies', async (req, res) => { + res.statusCode = 201 + await res.setCookie('cookie-1', 'value-1', { + domain: req.headers.host, + maxAge: 3600 + }) + .setCookie('cookie-2', 'value-2') + .send() + }) + app.get('/get-cookies', async (req, res) => { + await res.send(JSON.stringify(Object.entries(req.cookies).map(([key, value]) => `${key}=${value}`))) + }) + + await app.ready() + + if (server == null) { + throw new Error('Server not created') + } + + return server +} diff --git a/packages/interop/test/fixtures/create-fastify-websocket.ts b/packages/interop/test/fixtures/create-fastify-websocket.ts new file mode 100644 index 0000000..61bda2c --- /dev/null +++ b/packages/interop/test/fixtures/create-fastify-websocket.ts @@ -0,0 +1,50 @@ +import fastifyWebSocket from '@fastify/websocket' +import { toWebSocket } from '@libp2p/http-server/node' +import { fastify } from 'fastify' +import type { CanHandle } from '@libp2p/http-server/node' +import type { Server } from 'node:http' + +export async function createFastifyWebSocket (server: Server, handled?: CanHandle): Promise { + const app = fastify({ + serverFactory: (app, opts) => { + server.addListener('request', (req, res) => { + if (handled?.(req, res) === true) { + return + } + + res.setHeader('Access-Control-Allow-Origin', '*') + res.setHeader('Access-Control-Request-Method', '*') + res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST') + res.setHeader('Access-Control-Allow-Headers', '*') + + app(req, res) + }) + + return server + } + }) + await app.register(fastifyWebSocket) + await app.register(async function (fastify) { + fastify.get('/echo', { websocket: true }, (socket, req) => { + socket.on('message', message => { + socket.send(message) + }) + }) + fastify.get('/*', { websocket: true }, (socket, req) => { + if (handled?.(toWebSocket(socket, req.raw)) === true) { + return + } + + socket.send('Hello world!') + socket.close() + }) + }) + + await app.ready() + + if (server == null) { + throw new Error('Server not created') + } + + return server +} diff --git a/packages/interop/test/fixtures/create-http.ts b/packages/interop/test/fixtures/create-http.ts new file mode 100644 index 0000000..619fcf4 --- /dev/null +++ b/packages/interop/test/fixtures/create-http.ts @@ -0,0 +1,43 @@ +import type { CanHandle } from '@libp2p/http-server/node' +import type { Server, RequestListener } from 'node:http' + +export function createHttp (server: Server, handled?: CanHandle): Server { + const app: RequestListener = (req, res) => { + if (req.url === '/echo') { + req.pipe(res) + + return + } + + if (req.url === '/set-cookies') { + res.appendHeader('set-cookie', `cookie-1=value-1; Domain=${req.headers.host}; Max-Age=3600`) + res.appendHeader('set-cookie', 'cookie-2=value-2') + res.writeHead(201) + res.end() + + return + } + + if (req.url === '/get-cookies') { + res.end(JSON.stringify(req.headers.cookie?.split(';').map(s => s.trim()) ?? [])) + + return + } + + res.end('Hello World!') + } + + server.on('request', (req, res) => { + if (handled?.(req, res) === true) { + return + } + + res.setHeader('Access-Control-Allow-Origin', req.headers.origin ?? '*') + res.setHeader('Access-Control-Allow-Methods', ['OPTIONS', req.headers['access-control-request-method'] ?? '']) + res.setHeader('Access-Control-Allow-Headers', req.headers['access-control-request-headers'] ?? '*') + + app(req, res) + }) + + return server +} diff --git a/packages/interop/test/fixtures/create-websocket-server.ts b/packages/interop/test/fixtures/create-websocket-server.ts new file mode 100644 index 0000000..a523b4e --- /dev/null +++ b/packages/interop/test/fixtures/create-websocket-server.ts @@ -0,0 +1,42 @@ +import { createWebSocketServer as createWss } from '@libp2p/http-server/node' +import type { CanHandle } from '@libp2p/http-server/node' +import type { Server } from 'node:http' + +export function createWebSocketServer (server: Server, handled?: CanHandle): Server { + const wss = createWss() + wss.addEventListener('connection', (evt) => { + const ws = evt.webSocket + + if (handled?.(ws) === true) { + return + } + + if (ws.url === '/echo') { + ws.addEventListener('message', (evt) => { + ws.send(evt.data) + }) + } else { + ws.send('Hello world!') + ws.close() + } + }) + + server.on('request', (req, res) => { + if (handled?.(req, res) === true) { + return + } + + res.setHeader('Access-Control-Allow-Origin', '*') + res.setHeader('Access-Control-Request-Method', '*') + res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST') + res.setHeader('Access-Control-Allow-Headers', '*') + + res.writeHead(400) + res.end() + }) + server.on('upgrade', (request, socket, head) => { + wss.handleUpgrade(request, socket, head) + }) + + return server +} diff --git a/packages/interop/test/fixtures/create-wss.ts b/packages/interop/test/fixtures/create-wss.ts new file mode 100644 index 0000000..b99310d --- /dev/null +++ b/packages/interop/test/fixtures/create-wss.ts @@ -0,0 +1,43 @@ +import { toWebSocket } from '@libp2p/http-server/node' +import { WebSocketServer } from 'ws' +import type { CanHandle } from '@libp2p/http-server/node' +import type { Server } from 'node:http' + +export function createWss (server: Server, handled?: CanHandle): Server { + const wss = new WebSocketServer({ noServer: true }) + wss.on('connection', (ws, req) => { + if (handled?.(toWebSocket(ws, req)) === true) { + return + } + + if (req.url === '/echo') { + ws.on('message', (data) => { + ws.send(data) + }) + } else { + ws.send('Hello world!') + ws.close() + } + }) + + server.on('request', (req, res) => { + if (handled?.(req, res) === true) { + return + } + + res.setHeader('Access-Control-Allow-Origin', '*') + res.setHeader('Access-Control-Request-Method', '*') + res.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST') + res.setHeader('Access-Control-Allow-Headers', '*') + + res.writeHead(400) + res.end() + }) + server.on('upgrade', (request, socket, head) => { + wss.handleUpgrade(request, socket, head, (ws) => { + wss.emit('connection', ws, request) + }) + }) + + return server +} diff --git a/packages/interop/test/fixtures/get-libp2p.ts b/packages/interop/test/fixtures/get-libp2p.ts new file mode 100644 index 0000000..f9d8c83 --- /dev/null +++ b/packages/interop/test/fixtures/get-libp2p.ts @@ -0,0 +1,159 @@ +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { http, authenticatedRoute, authenticatedWebSocketRoute } from '@libp2p/http' +import { pingHTTP } from '@libp2p/http-ping' +import { memory } from '@libp2p/memory' +import { ping } from '@libp2p/ping' +import { webSockets } from '@libp2p/websockets' +import { createLibp2p } from 'libp2p' +import type { WebServer, HTTP } from '@libp2p/http' +import type { PingHTTP } from '@libp2p/http-ping' +import type { Libp2p } from '@libp2p/interface' + +function addEndpoints (libp2p: Libp2p<{ http: HTTP }>): void { + libp2p.services.http.handle('/libp2p/http/echo', { + method: 'POST', + handler: async (req) => { + if (req.body == null) { + return new Response(undefined, { + status: 400 + }) + } + + const body = new TransformStream() + const res = new Response(body.readable) + + req.body?.pipeTo(body.writable) + .catch(err => { + body.writable.abort(err) + .catch(() => {}) + }) + + return res + } + }) + + libp2p.services.http.handle('/libp2p/http/peer-id', authenticatedRoute({ + method: 'GET', + handler: async (req, peerId) => { + return new Response(peerId.toString(), { + status: 200 + }) + } + })) + + libp2p.services.http.handle('/libp2p/http/optional-peer-id', authenticatedRoute({ + method: 'GET', + requireAuth: false, + handler: async (req, peerId) => { + return new Response(peerId?.toString() ?? 'no-peer-id', { + status: 200 + }) + } + })) + + libp2p.services.http.handle('/libp2p/http/ws-peer-id', authenticatedWebSocketRoute({ + method: 'GET', + handler: (ws, peerId) => { + ws.send(peerId.toString()) + ws.close() + }, + fallback: async (req, peerId) => { + return new Response(peerId.toString(), { + status: 200 + }) + } + })) + + libp2p.services.http.handle('/libp2p/http/ws-optional-peer-id', authenticatedWebSocketRoute({ + method: 'GET', + requireAuth: false, + handler: (ws, peerId) => { + ws.send(peerId?.toString() ?? 'no-peer-id') + ws.close() + }, + fallback: async (req, peerId) => { + return new Response(peerId?.toString() ?? 'no-peer-id', { + status: 200 + }) + } + })) +} + +/** + * A node that listens for incoming HTTP over libp2p requests + */ +export async function getHTTPOverLibp2pHandler (server: WebServer, listen: string = '/memory/address-1'): Promise> { + const libp2p = await createLibp2p({ + addresses: { + listen: [ + listen + ] + }, + transports: [ + webSockets(), + memory() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http({ server }), + ping: ping(), + pingHTTP: pingHTTP() + }, + connectionManager: { + inboundConnectionThreshold: Infinity + } + }) + + addEndpoints(libp2p) + + return libp2p +} + +/** + * A client node that makes HTTP over libp2p requests + */ +export async function getClient (): Promise> { + return createLibp2p({ + transports: [ + webSockets(), + memory() + ], + connectionEncrypters: [ + noise() + ], + streamMuxers: [ + yamux() + ], + services: { + http: http(), + ping: ping(), + pingHTTP: pingHTTP() + } + }) +} + +/** + * A node that does not listen on any addresses but processes incoming libp2p + * over HTTP requests + */ +export async function getLibp2pOverHttpHandler (): Promise< Libp2p<{ http: HTTP, pingHTTP: PingHTTP }>> { + const libp2p = await createLibp2p({ + services: { + http: http(), + pingHTTP: pingHTTP() + }, + connectionManager: { + inboundConnectionThreshold: Infinity + } + }) + + addEndpoints(libp2p) + + return libp2p +} diff --git a/packages/interop/test/peer-id-auth.spec.ts b/packages/interop/test/peer-id-auth.spec.ts new file mode 100644 index 0000000..95d6b23 --- /dev/null +++ b/packages/interop/test/peer-id-auth.spec.ts @@ -0,0 +1,326 @@ +import { peerIdAuth } from '@libp2p/http/middleware' +import { nodeServer } from '@libp2p/http-server' +import { createServer } from '@libp2p/http-server/node' +import { stop } from '@libp2p/interface' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' +import pDefer from 'p-defer' +import { pEvent } from 'p-event' +import { createHttp } from './fixtures/create-http.js' +import { getClient, getHTTPOverLibp2pHandler } from './fixtures/get-libp2p.js' +import type { HTTP } from '@libp2p/http' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Libp2p } from 'libp2p' + +interface Test { + name: string + startServer(): Promise + stopServer(): Promise +} + +let listener: Libp2p<{ http: HTTP }> + +const tests: Test[] = [{ + name: 'in-process server', + startServer: async () => { + listener = await getHTTPOverLibp2pHandler(nodeServer(createHttp(createServer()))) + + return listener.getMultiaddrs() + }, + stopServer: async () => { + await stop(listener) + } +}, { + name: 'js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_HTTP_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_HTTP_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'express/js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_EXPRESS_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'express/node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_EXPRESS_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'fastify/js', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_JS_FASTIFY_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}, { + name: 'fastify/node:http', + startServer: async () => { + return [ + multiaddr(process.env.LIBP2P_NODE_FASTIFY_MULTIADDR ?? '') + ] + }, + stopServer: async () => { + + } +}] + +for (const test of tests) { + describe(`peer id auth - HTTP over libp2p - ${test.name}`, () => { + let client: Libp2p<{ http: HTTP }> + let listenerMultiaddrs: Multiaddr[] + + beforeEach(async () => { + client = await getClient() + listenerMultiaddrs = await test.startServer() + }) + + afterEach(async () => { + await stop(client) + await test.stopServer() + }) + + it('should support peer id auth', async () => { + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal(client.peerId.toString()) + }) + + it('should support optional peer id auth', async () => { + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/optional-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal(client.peerId.toString()) + }) + + it('should support optional peer id auth without auth', async () => { + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/optional-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + } + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal('no-peer-id') + }) + + it('should support WebSocket peer id auth', async () => { + const deferred = pDefer() + const socket = await client.services.http.connect(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/ws-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + + if (socket.readyState !== WebSocket.OPEN) { + await pEvent(socket, 'open') + } + + socket.addEventListener('error', (evt: any) => { + deferred.reject(evt.error) + }) + socket.addEventListener('close', () => { + deferred.reject(new Error('Socket closed before message received')) + }) + socket.addEventListener('message', (evt) => { + deferred.resolve(new TextDecoder().decode(evt.data)) + }) + + await expect(deferred.promise).to.eventually.equal(client.peerId.toString()) + }) + + it('should support WebSocket optional peer id auth', async () => { + const deferred = pDefer() + const socket = await client.services.http.connect(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/ws-optional-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + + if (socket.readyState !== WebSocket.OPEN) { + await pEvent(socket, 'open') + } + + socket.addEventListener('error', (evt: any) => { + deferred.reject(evt.error) + }) + socket.addEventListener('close', () => { + deferred.reject(new Error('Socket closed before message received')) + }) + socket.addEventListener('message', (evt) => { + deferred.resolve(new TextDecoder().decode(evt.data)) + }) + + await expect(deferred.promise).to.eventually.equal(client.peerId.toString()) + }) + + it('should support WebSocket optional peer id auth without auth', async () => { + const deferred = pDefer() + const socket = await client.services.http.connect(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/ws-optional-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + } + }) + + if (socket.readyState !== WebSocket.OPEN) { + await pEvent(socket, 'open') + } + + socket.addEventListener('error', (evt: any) => { + deferred.reject(evt.error) + }) + socket.addEventListener('close', () => { + deferred.reject(new Error('Socket closed before message received')) + }) + socket.addEventListener('message', (evt) => { + deferred.resolve(new TextDecoder().decode(evt.data)) + }) + + await expect(deferred.promise).to.eventually.equal('no-peer-id') + }) + + it('should fall back to HTTP on WebSocket route with peer id auth', async () => { + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/ws-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal(client.peerId.toString()) + }) + + it('should fall back to HTTP on WebSocket route with optional peer id auth', async () => { + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/ws-optional-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal(client.peerId.toString()) + }) + + it('should fall back to HTTP on WebSocket route with optional peer id auth without auth', async () => { + const response = await client.services.http.fetch(listenerMultiaddrs.map(ma => ma.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/ws-optional-peer-id')}`)), { + headers: { + host: 'test-with-auth.com' + } + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal('no-peer-id') + }) + }) +} + +const HTTP_SERVERS = [{ + name: 'node:http', + address: multiaddr(process.env.HTTP_NODE_HTTP_MULTIADDR) +}, { + name: 'express', + address: multiaddr(process.env.HTTP_EXPRESS_MULTIADDR) +}, { + name: 'fastify', + address: multiaddr(process.env.HTTP_FASTIFY_MULTIADDR) +}] + +HTTP_SERVERS.forEach(test => { + describe(`peer id auth - libp2p over HTTP - ${test.name}`, () => { + let client: Libp2p<{ http: HTTP }> + let httpAddr: Multiaddr + + beforeEach(async () => { + client = await getClient() + httpAddr = multiaddr(test.address) + }) + + afterEach(async () => { + await stop(client) + }) + + it('should support peer id auth', async () => { + const response = await client.services.http.fetch(httpAddr.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/peer-id')}`), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal(client.peerId.toString()) + }) + + it('should support optional peer id auth', async () => { + const response = await client.services.http.fetch(httpAddr.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/optional-peer-id')}`), { + headers: { + host: 'test-with-auth.com' + }, + middleware: [ + peerIdAuth() + ] + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal(client.peerId.toString()) + }) + + it('should support optional peer id auth without auth', async () => { + const response = await client.services.http.fetch(httpAddr.encapsulate(`/http-path/${encodeURIComponent('libp2p/http/optional-peer-id')}`), { + headers: { + host: 'test-with-auth.com' + } + }) + expect(response.status).to.equal(200) + await expect(response.text()).to.eventually.equal('no-peer-id') + }) + }) +}) diff --git a/packages/interop/test/ping.spec.ts b/packages/interop/test/ping.spec.ts new file mode 100644 index 0000000..b0bac19 --- /dev/null +++ b/packages/interop/test/ping.spec.ts @@ -0,0 +1,269 @@ +/* eslint-env mocha */ + +import { noise } from '@chainsafe/libp2p-noise' +import { yamux } from '@chainsafe/libp2p-yamux' +import { generateKeyPair } from '@libp2p/crypto/keys' +import { http } from '@libp2p/http' +import { peerIdAuth } from '@libp2p/http/middleware' +import { pingHTTP } from '@libp2p/http-ping' +import { stop } from '@libp2p/interface' +import { peerIdFromPrivateKey } from '@libp2p/peer-id' +import { webSockets } from '@libp2p/websockets' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' +import { createLibp2p } from 'libp2p' +import sinon from 'sinon' +import type { HTTP } from '@libp2p/http' +import type { PingHTTP } from '@libp2p/http-ping' +import type { Libp2p } from '@libp2p/interface' + +const LIBP2P_SERVERS = [{ + name: 'node:http', + address: multiaddr(process.env.LIBP2P_JS_HTTP_MULTIADDR) +}, { + name: 'js', + address: multiaddr(process.env.LIBP2P_NODE_HTTP_MULTIADDR) +}, { + name: 'express/js', + address: multiaddr(process.env.LIBP2P_JS_EXPRESS_MULTIADDR) +}, { + name: 'express/node:http', + address: multiaddr(process.env.LIBP2P_NODE_EXPRESS_MULTIADDR) +}, { + name: 'fastify/js', + address: multiaddr(process.env.LIBP2P_JS_FASTIFY_MULTIADDR) +}, { + name: 'fastify/node:http', + address: multiaddr(process.env.LIBP2P_NODE_FASTIFY_MULTIADDR) +}] + +describe('ping - HTTP over libp2p', () => { + let client: Libp2p<{ http: HTTP, pingHTTP: PingHTTP }> + + beforeEach(async () => { + client = await createLibp2p({ + transports: [ + webSockets() + ], + streamMuxers: [ + yamux() + ], + connectionEncrypters: [ + noise() + ], + services: { + http: http(), + pingHTTP: pingHTTP() + } + }) + }) + + afterEach(async () => { + await stop(client) + }) + + LIBP2P_SERVERS.forEach(test => { + it(`should perform ping with ${test.name} server`, async () => { + await expect(client.services.pingHTTP.ping(multiaddr(test.address))).to.eventually.be.a('number') + }) + }) +}) + +const HTTP_SERVERS = [{ + name: 'node:http', + address: multiaddr(process.env.HTTP_NODE_HTTP_MULTIADDR) +}, { + name: 'express', + address: multiaddr(process.env.HTTP_EXPRESS_MULTIADDR) +}, { + name: 'fastify', + address: multiaddr(process.env.HTTP_FASTIFY_MULTIADDR) +}] + +describe('ping - libp2p over HTTP', () => { + let client: Libp2p<{ http: HTTP, pingHTTP: PingHTTP }> + + beforeEach(async () => { + client = await createLibp2p({ + services: { + http: http(), + pingHTTP: pingHTTP() + } + }) + }) + + afterEach(async () => { + await stop(client) + }) + + HTTP_SERVERS.forEach(test => { + it(`should perform ping with the HTTP address of a ${test.name} server`, async () => { + const httpAddr = multiaddr(test.address) + + await expect(client.services.pingHTTP.ping(httpAddr)).to.eventually.be.a('number') + }) + + it(`should perform ping with a HTTP address with a peer id of a ${test.name} server`, async () => { + const httpAddr = multiaddr(test.address).encapsulate(`/p2p/${process.env.HTTP_PEER_ID}`) + const verifyPeer = sinon.stub().callsFake((peerId) => { + return peerId.equals(httpAddr.getPeerId()) + }) + + await expect(client.services.pingHTTP.ping(httpAddr, { + middleware: [ + peerIdAuth({ + verifyPeer + }) + ] + })).to.eventually.be.a('number') + + expect(verifyPeer).to.have.property('called', true) + }) + + it(`should reject when performing ping with a HTTP address with the wrong peer id of a ${test.name} server`, async () => { + const privateKey = await generateKeyPair('Ed25519') + const peerId = peerIdFromPrivateKey(privateKey) + + const httpAddr = multiaddr(test.address).encapsulate(`/p2p/${peerId}`) + const verifyPeer = sinon.stub().callsFake((peerId) => { + return peerId.equals(httpAddr.getPeerId()) + }) + + await expect(client.services.pingHTTP.ping(httpAddr, { + middleware: [ + peerIdAuth({ + verifyPeer + }) + ] + })).to.eventually.be.rejected + .with.property('name', 'InvalidPeerError') + + expect(verifyPeer).to.have.property('called', true) + }) + }) +}) + +const WS_SERVERS = [{ + name: 'ws', + address: multiaddr(process.env.WS_WSS_MULTIADDR) +}, { + name: '@fastify/websocket', + address: multiaddr(process.env.WS_FASTIFY_MULTIADDR) +}] + +describe('ping - libp2p over WebSockets', () => { + let client: Libp2p<{ http: HTTP, pingHTTP: PingHTTP }> + + beforeEach(async () => { + client = await createLibp2p({ + services: { + http: http(), + pingHTTP: pingHTTP() + } + }) + }) + + afterEach(async () => { + await stop(client) + }) + + WS_SERVERS.forEach(test => { + it(`should perform ping with the WebSocket address of a ${test.name} server`, async () => { + const httpAddr = multiaddr(test.address) + + await expect(client.services.pingHTTP.ping(httpAddr, { + webSocket: true + })).to.eventually.be.a('number') + }) + + it(`should perform ping with a WebSocket address with a peer id of a ${test.name} server`, async () => { + const httpAddr = multiaddr(test.address).encapsulate(`/p2p/${process.env.HTTP_PEER_ID}`) + const verifyPeer = sinon.stub().callsFake((peerId) => { + return peerId.equals(httpAddr.getPeerId()) + }) + + await expect(client.services.pingHTTP.ping(httpAddr, { + webSocket: true, + middleware: [ + peerIdAuth({ + verifyPeer + }) + ] + })).to.eventually.be.a('number') + + expect(verifyPeer).to.have.property('called', true) + }) + + it(`should reject when performing ping with a WebSocket address with the wrong peer id of a ${test.name} server`, async () => { + const privateKey = await generateKeyPair('Ed25519') + const peerId = peerIdFromPrivateKey(privateKey) + + const httpAddr = multiaddr(test.address).encapsulate(`/p2p/${peerId}`) + const verifyPeer = sinon.stub().callsFake((peerId) => { + return peerId.equals(httpAddr.getPeerId()) + }) + + await expect(client.services.pingHTTP.ping(httpAddr, { + webSocket: true, + middleware: [ + peerIdAuth({ + verifyPeer + }) + ] + })).to.eventually.be.rejected + .with.property('name', 'InvalidPeerError') + + expect(verifyPeer).to.have.property('called', true) + }) + }) +}) + +const LIBP2P_WS_SERVERS = [{ + name: 'ws/js', + address: multiaddr(process.env.LIBP2P_JS_WSS_MULTIADDR) +}, { + name: 'ws/node:http', + address: multiaddr(process.env.LIBP2P_NODE_WSS_MULTIADDR) +}, { + name: '@fastify/websocket/js', + address: multiaddr(process.env.LIBP2P_JS_FASTIFY_WS_MULTIADDR) +}, { + name: '@fastify/websocket/node:http', + address: multiaddr(process.env.LIBP2P_NODE_FASTIFY_WS_MULTIADDR) +}] + +describe('ping - WebSockets over libp2p', () => { + let client: Libp2p<{ http: HTTP, pingHTTP: PingHTTP }> + + beforeEach(async () => { + client = await createLibp2p({ + transports: [ + webSockets() + ], + streamMuxers: [ + yamux() + ], + connectionEncrypters: [ + noise() + ], + services: { + http: http(), + pingHTTP: pingHTTP() + } + }) + }) + + afterEach(async () => { + await stop(client) + }) + + LIBP2P_WS_SERVERS.forEach(test => { + it(`should perform ping with the WebSocket address of a ${test.name} server`, async () => { + const httpAddr = multiaddr(test.address) + + await expect(client.services.pingHTTP.ping(httpAddr, { + webSocket: true + })).to.eventually.be.a('number') + }) + }) +}) diff --git a/packages/interop/test/websockets.spec.ts b/packages/interop/test/websockets.spec.ts new file mode 100644 index 0000000..3598a4b --- /dev/null +++ b/packages/interop/test/websockets.spec.ts @@ -0,0 +1,166 @@ +import { nodeServer } from '@libp2p/http-server' +import { createServer } from '@libp2p/http-server/node' +import { stop } from '@libp2p/interface' +import { multiaddr } from '@multiformats/multiaddr' +import { expect } from 'aegir/chai' +import pDefer from 'p-defer' +import { createWebSocketServer } from './fixtures/create-websocket-server.js' +import { getClient, getHTTPOverLibp2pHandler } from './fixtures/get-libp2p.js' +import type { HTTP } from '@libp2p/http' +import type { Multiaddr } from '@multiformats/multiaddr' +import type { Libp2p } from 'libp2p' + +interface Test { + name: string + startServer(): Promise + stopServer(): Promise +} + +let listener: Libp2p<{ http: HTTP }> + +const LIBP2P_SERVERS: Test[] = [{ + name: 'in-process server', + startServer: async () => { + const server = createWebSocketServer(createServer()) + + listener = await getHTTPOverLibp2pHandler(nodeServer(server)) + return listener.getMultiaddrs()[0] + }, + stopServer: async () => { + await stop(listener) + } +}, { + name: 'ws/js', + startServer: async () => { + return multiaddr(process.env.LIBP2P_JS_WSS_MULTIADDR ?? '') + }, + stopServer: async () => { + + } +}, { + name: 'ws/node:http', + startServer: async () => { + return multiaddr(process.env.LIBP2P_NODE_WSS_MULTIADDR ?? '') + }, + stopServer: async () => { + + } +}, { + name: '@fastify/websocket/js', + startServer: async () => { + return multiaddr(process.env.LIBP2P_JS_FASTIFY_WS_MULTIADDR ?? '') + }, + stopServer: async () => { + + } +}, { + name: '@fastify/websocket/node:http', + startServer: async () => { + return multiaddr(process.env.LIBP2P_NODE_FASTIFY_WS_MULTIADDR ?? '') + }, + stopServer: async () => { + + } +}] + +for (const test of LIBP2P_SERVERS) { + describe(`WebSockets over libp2p - ${test.name}`, () => { + let client: Libp2p<{ http: HTTP }> + let address: Multiaddr + + beforeEach(async () => { + client = await getClient() + address = await test.startServer() + }) + + afterEach(async () => { + await stop(client) + await test.stopServer() + }) + + it('should make an WebSocket request to echo', async () => { + const deferred = pDefer() + const message = 'This should be echoed' + const socket = await client.services.http.connect(address.encapsulate('/http-path/echo'), { + headers: { + host: 'example.com' + } + }) + socket.addEventListener('error', (evt: any) => { + deferred.reject(evt.error) + }) + socket.addEventListener('close', () => { + deferred.reject(new Error('Socket closed before message received')) + }) + socket.addEventListener('message', (evt) => { + deferred.resolve(evt.data) + }) + socket.addEventListener('open', () => { + socket.send(message) + }) + + expect(new TextDecoder().decode(await deferred.promise)).to.equal(message) + }) + }) +} + +const HTTP_SERVERS: Test[] = [{ + name: 'ws', + startServer: async () => { + return multiaddr(process.env.WS_WSS_MULTIADDR ?? '') + }, + stopServer: async () => { + + } +}, { + name: '@fastify/websocket', + startServer: async () => { + return multiaddr(process.env.WS_FASTIFY_MULTIADDR ?? '') + }, + stopServer: async () => { + + } +}] + +for (const test of HTTP_SERVERS) { + describe(`libp2p over WebSockets - ${test.name}`, () => { + let client: Libp2p<{ http: HTTP }> + let address: Multiaddr + let socket: WebSocket + + beforeEach(async () => { + client = await getClient() + address = await test.startServer() + }) + + afterEach(async () => { + socket?.close() + await stop(client) + await test.stopServer() + }) + + it('should make an WebSocket request to echo', async () => { + const deferred = pDefer() + const message = 'This should be echoed' + socket = await client.services.http.connect(address.encapsulate('/http-path/echo'), { + headers: { + host: 'example.com' + } + }) + socket.addEventListener('error', (evt: any) => { + deferred.reject(evt.error) + }) + socket.addEventListener('close', () => { + deferred.reject(new Error('Socket closed before message received')) + }) + socket.addEventListener('message', (evt) => { + deferred.resolve(evt.data) + }) + socket.addEventListener('open', () => { + socket.send(message) + }) + + expect(new TextDecoder().decode(await deferred.promise)).to.equal(message) + }) + }) +} diff --git a/packages/interop/tsconfig.json b/packages/interop/tsconfig.json new file mode 100644 index 0000000..06c3375 --- /dev/null +++ b/packages/interop/tsconfig.json @@ -0,0 +1,21 @@ +{ + "extends": "aegir/src/config/tsconfig.aegir.json", + "compilerOptions": { + "outDir": "dist" + }, + "include": [ + "src", + "test" + ], + "references": [ + { + "path": "../http" + }, + { + "path": "../http-ping" + }, + { + "path": "../http-server" + } + ] +} diff --git a/src/auth/agent.browser.ts b/src/auth/agent.browser.ts deleted file mode 100644 index 89b03bc..0000000 --- a/src/auth/agent.browser.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Returns nothing as browsers handle cookies for us - */ -export function getAgent (): any { - return { - agent: undefined, - jar: { - getCookies: () => [] - } - } -} diff --git a/src/auth/agent.ts b/src/auth/agent.ts deleted file mode 100644 index 3dde110..0000000 --- a/src/auth/agent.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { CookieAgent } from 'http-cookie-agent/undici' -import { CookieJar } from 'tough-cookie' - -/** - * Returns an HTTP Agent that handles cookies over multiple requests - */ -export function getAgent (): { agent: CookieAgent, jar: CookieJar } { - const jar = new CookieJar() - - return { - agent: new CookieAgent({ - cookies: { - jar - } - }), - jar - } -} diff --git a/src/auth/client.ts b/src/auth/client.ts deleted file mode 100644 index df69c1e..0000000 --- a/src/auth/client.ts +++ /dev/null @@ -1,250 +0,0 @@ -import { publicKeyFromProtobuf, publicKeyToProtobuf } from '@libp2p/crypto/keys' -import { peerIdFromPublicKey } from '@libp2p/peer-id' -import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' -import { getAgent } from './agent.js' -import { parseHeader, PeerIDAuthScheme, sign, verify } from './common.js' -import { BadResponseError, InvalidPeerError, InvalidSignatureError, MissingAuthHeaderError } from './errors.js' -import type { PeerId, PrivateKey } from '@libp2p/interface' -import type { AbortOptions } from '@multiformats/multiaddr' -import type { CookieAgent } from 'http-cookie-agent/undici' -import type { CookieJar } from 'tough-cookie' - -export interface TokenInfo { - creationTime: Date - bearer: string - peer: PeerId - agent: CookieAgent - jar: CookieJar -} - -export interface AuthenticatedFetchOptions extends RequestInit { - /** - * The Fetch implementation to use - * - * @default globalThis.fetch - */ - fetch?: typeof globalThis.fetch - - /** - * The hostname to use - by default this will be extracted from the `.host` - * property of `authEndpointURI` - */ - hostname?: string - - /** - * A function to verify the peer ID of the server. This function - * will be called after the server has authenticated itself. - * If the function returns false, the request will be aborted. - */ - verifyPeer?(peerId: PeerId, options: AbortOptions): boolean | Promise -} - -export interface AuthenticateServerOptions extends AbortOptions { - /** - * The Fetch implementation to use - * - * @default globalThis.fetch - */ - fetch?: AuthenticatedFetchOptions['fetch'] - - /** - * The hostname to use - by default this will be extracted from the `.host` - * property of `authEndpointURI` - */ - hostname?: AuthenticatedFetchOptions['hostname'] -} - -interface DoAuthenticatedFetchOptions { - fetch?: AuthenticatedFetchOptions['fetch'] - hostname?: AuthenticatedFetchOptions['hostname'] -} - -export class ClientAuth { - key: PrivateKey - tokens = new Map() // A map from hostname to token - tokenTTL = 60 * 60 * 1000 // 1 hour - - constructor (key: PrivateKey, opts?: { tokenTTL?: number }) { - this.key = key - if (opts?.tokenTTL !== undefined) { - this.tokenTTL = opts.tokenTTL - } - } - - private generateChallenge (): string { - const randomBytes = new Uint8Array(32) - crypto.getRandomValues(randomBytes) - return uint8ArrayToString(randomBytes, 'base64urlpad') - } - - private encodeAuthParams (params: Record): string { - const encodedParams = Object.entries(params) - .map(([key, value]) => `${key}="${value}"`) - .join(', ') - return `${PeerIDAuthScheme} ${encodedParams}` - } - - public bearerAuthHeaderWithPeer (hostname: string): { 'authorization': string, peer: PeerId, agent: CookieAgent, jar: CookieJar } | undefined { - const token = this.tokens.get(hostname) - if (token == null) { - return undefined - } - if (Date.now() - token.creationTime.getTime() > this.tokenTTL) { - this.tokens.delete(hostname) - return undefined - } - return { - authorization: `${PeerIDAuthScheme} bearer="${token.bearer}"`, - peer: token.peer, - agent: token.agent, - jar: token.jar - } - } - - public bearerAuthHeader (hostname: string): string | undefined { - return this.bearerAuthHeaderWithPeer(hostname)?.authorization - } - - /** - * authenticatedFetch is like `fetch`, but it also handles HTTP Peer ID - * authentication with the server. - * - * If we have not seen the server before, verifyPeer will be called to check - * if we want to make the request to the server with the given peer id. This - * happens after we've authenticated the server. - */ - public async authenticatedFetch (request: string | URL | Request, options?: AuthenticatedFetchOptions): Promise { - const { fetch, hostname, verifyPeer, ...requestOpts } = options ?? {} - let req: Request - if (request instanceof Request && Object.keys(requestOpts).length === 0) { - req = request - } else { - req = new Request(request, requestOpts) - } - const verifyPeerWithDefault = verifyPeer ?? (() => true) - - const { response, peer } = await this.doAuthenticatedFetch(req, verifyPeerWithDefault, { fetch, hostname }) - - const responseWithPeer: Response & { peer: PeerId } = response as Response & { peer: PeerId } - responseWithPeer.peer = peer - return responseWithPeer - } - - private async doAuthenticatedFetch (request: Request, verifyPeer: (server: PeerId, options: AbortOptions) => boolean | Promise, options?: DoAuthenticatedFetchOptions): Promise<{ peer: PeerId, response: Response }> { - const authEndpointURI = new URL(request.url) - const hostname = options?.hostname ?? authEndpointURI.host - const fetch = options?.fetch ?? globalThis.fetch - - if (this.tokens.has(hostname)) { - const token = this.bearerAuthHeaderWithPeer(hostname) - if (token !== undefined) { - // @ts-expect-error not in types - request.dispatcher = token.agent - request.headers.set('Authorization', token.authorization) - - await addCookiesToRequest(request, token.jar) - - return { peer: token.peer, response: await fetch(request) } - } else { - this.tokens.delete(hostname) - } - } - - // Client initiated handshake (server initiated is not implemented yet) - const marshaledClientPubKey = publicKeyToProtobuf(this.key.publicKey) - const publicKeyStr = uint8ArrayToString(marshaledClientPubKey, 'base64urlpad') - const challengeServer = this.generateChallenge() - const headers = { - Authorization: this.encodeAuthParams({ - 'challenge-server': challengeServer, - 'public-key': publicKeyStr - }) - } - - const { agent, jar } = getAgent() - - const resp = await fetch(authEndpointURI, { - method: 'OPTIONS', - headers, - signal: request.signal, - - // @ts-expect-error not in types - dispatcher: agent - }) - - // Verify the server's challenge - const authHeader = resp.headers.get('www-authenticate') - if (authHeader == null) { - throw new MissingAuthHeaderError('No auth header') - } - const authFields = parseHeader(authHeader) - const serverPubKeyBytes = uint8ArrayFromString(authFields['public-key'], 'base64urlpad') - const serverPubKey = publicKeyFromProtobuf(serverPubKeyBytes) - - const valid = await verify(serverPubKey, PeerIDAuthScheme, [ - ['hostname', hostname], - ['client-public-key', marshaledClientPubKey], - ['challenge-server', challengeServer]], uint8ArrayFromString(authFields.sig, 'base64urlpad')) - if (!valid) { - throw new InvalidSignatureError('Invalid signature') - } - - const serverPublicKey = publicKeyFromProtobuf(serverPubKeyBytes) - const serverID = peerIdFromPublicKey(serverPublicKey) - - if (!await verifyPeer(serverID, { signal: request.signal })) { - throw new InvalidPeerError('Id check failed') - } - - const sig = await sign(this.key, PeerIDAuthScheme, [ - ['hostname', hostname], - ['server-public-key', serverPubKeyBytes], - ['challenge-client', authFields['challenge-client']]]) - - const authenticateSelfHeaders = this.encodeAuthParams({ - opaque: authFields.opaque, - sig: uint8ArrayToString(sig, 'base64urlpad') - }) - - // @ts-expect-error not in types - request.dispatcher = agent - request.headers.set('Authorization', authenticateSelfHeaders) - - await addCookiesToRequest(request, jar) - - const resp2 = await fetch(request) - - if (!resp2.ok) { - throw new BadResponseError(`Unexpected status code ${resp2.status}`) - } - - const serverAuthHeader = resp2.headers.get('Authentication-Info') - if (serverAuthHeader == null) { - throw new MissingAuthHeaderError('No server auth header') - } - - const serverAuthFields = parseHeader(serverAuthHeader) - this.tokens.set(hostname, { - peer: serverID, - creationTime: new Date(), - bearer: serverAuthFields.bearer, - agent, - jar - }) - - return { peer: serverID, response: resp2 } - } - - public async authenticateServer (authEndpointURI: string | URL, options?: AuthenticateServerOptions): Promise { - const req = new Request(authEndpointURI, { signal: options?.signal }) - return (await this.authenticatedFetch(req, options)).peer - } -} - -async function addCookiesToRequest (request: Request, jar: CookieJar): Promise { - const cookies = await jar.getCookies(request.url.toString()) - - cookies.forEach(cookie => { - request.headers.append('Cookie', cookie.cookieString()) - }) -} diff --git a/src/auth/common.ts b/src/auth/common.ts deleted file mode 100644 index 1396b33..0000000 --- a/src/auth/common.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as varint from 'uint8-varint' -import type { PrivateKey, PublicKey } from '@libp2p/interface' - -export const PeerIDAuthScheme = 'libp2p-PeerID' -export const HTTPPeerIDAuthProto = '/http-peer-id-auth/1.0.0' - -export async function sign (key: PrivateKey, prefix: string, partsToSign: Array<[string, string | Uint8Array]>): Promise { - const dataToSign = genDataToSign(prefix, partsToSign) - return key.sign(dataToSign) -} - -export async function verify (key: PublicKey, prefix: string, partsToSign: Array<[string, string | Uint8Array]>, sig: Uint8Array): Promise { - const dataToSign = genDataToSign(prefix, partsToSign) - return key.verify(dataToSign, sig) -} - -export function encodeAuthParams (params: Record): string { - const encodedParams = Object.entries(params) - .map(([key, value]) => `${key}="${value}"`) - .join(', ') - return `${PeerIDAuthScheme} ${encodedParams}` -} - -const textEncoder = new TextEncoder() - -function sizeOfPart ([k, v]: [string, string | Uint8Array]): number { - return k.length + 1 + v.length // key + '=' + value -} - -function genDataToSign (prefix: string, partsToSign: Array<[string, string | Uint8Array]>): Uint8Array { - // Sort the parts - partsToSign.sort((a, b) => a[0].localeCompare(b[0])) - const size = partsToSign.reduce((acc, p) => acc + varint.encodingLength(sizeOfPart(p)) + sizeOfPart(p), prefix.length) - const out = new Uint8Array(size) - let offset = 0 - const res = textEncoder.encodeInto(prefix, out) - offset += res.written - for (const [k, v] of partsToSign) { - const len = sizeOfPart([k, v]) - varint.encodeUint8Array(len, out, offset) - offset += varint.encodingLength(len) - let res = textEncoder.encodeInto(k, out.subarray(offset)) - offset += res.written - res = textEncoder.encodeInto('=', out.subarray(offset)) - offset += res.written - if (typeof v === 'string') { - res = textEncoder.encodeInto(v, out.subarray(offset)) - offset += res.written - } else { - out.set(v, offset) - offset += v.length - } - } - return out -} - -const maxAuthHeaderSize = 2048 - -export function parseHeader (headerVal: string): Record { - if (headerVal.length > maxAuthHeaderSize) { - throw new Error('header too long') - } - - if (!headerVal.includes(PeerIDAuthScheme)) { - throw new Error('no peer id auth scheme found') - } - - const rest = headerVal.substring(PeerIDAuthScheme.length).trim() - const params: Record = {} - const regex = /(\w[^=]+)="([^"]+)"/g - let match - while ((match = regex.exec(rest)) !== null) { - params[match[1]] = match[2] - } - return params -} diff --git a/src/auth/index.ts b/src/auth/index.ts deleted file mode 100644 index c9888f3..0000000 --- a/src/auth/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { PeerIDAuthScheme, HTTPPeerIDAuthProto } from './common.js' -export { ClientAuth } from './client.js' -export { ServerAuth } from './server.js' - -export type { AuthenticatedFetchOptions, AuthenticateServerOptions, TokenInfo } from './client.js' -export type { ServerAuthOps, HttpHandler } from './server.js' diff --git a/src/auth/server.ts b/src/auth/server.ts deleted file mode 100644 index cf49222..0000000 --- a/src/auth/server.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { publicKeyFromProtobuf, publicKeyToProtobuf } from '@libp2p/crypto/keys' -import { peerIdFromPublicKey, peerIdFromString } from '@libp2p/peer-id' -import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' -import { encodeAuthParams, parseHeader, PeerIDAuthScheme, sign, verify } from './common.js' -import type { PeerId, PrivateKey, PublicKey, Logger } from '@libp2p/interface' -import type http from 'node:http' - -export interface HttpHandler { (req: Request): Promise } - -export interface ServerAuthOps { - logger?: Logger - tokenTTL?: number -} - -export class ServerAuth { - private readonly key: PrivateKey - private readonly validHostname: (hostname: string) => boolean - private readonly tokenTTL = 60 * 60 * 1000 // 1 hour - private readonly logger?: Logger - - constructor (key: PrivateKey, validHostnames: (hostname: string) => boolean, opts?: ServerAuthOps) { - this.key = key - this.validHostname = validHostnames - this.logger = opts?.logger - if (opts?.tokenTTL !== undefined) { - this.tokenTTL = opts.tokenTTL - } - } - - httpHandler = this.withAuth.bind(this)(async (_peer, _req) => { - return new Response('', { status: 200 }) - }) - - withAuth (httpAuthedHandler: (peer: PeerId, req: Request) => Promise): HttpHandler { - return async (req: Request): Promise => { - const authResp = await this.authenticateRequest(this.readHostname(req), req.headers.get('Authorization') ?? undefined) - if (authResp.status !== 200 || authResp.peer === undefined) { - return new Response('', { status: authResp.status, headers: authResp.headers }) - } - - const innerHandlerResp = await httpAuthedHandler(authResp.peer, req) - - const mergedHeaders: Record = {} - // Merge using for of to only bring in actual fields from the headers (no - // inner symbols) - for (const [key, value] of innerHandlerResp.headers) { - mergedHeaders[key] = value - } - if (authResp.headers !== undefined) { - for (const [key, value] of Object.entries(authResp.headers)) { - mergedHeaders[key] = value - } - } - - return new Response(innerHandlerResp.body, { status: innerHandlerResp.status, headers: mergedHeaders }) - } - } - - requestListener (httpAuthedHandler: (peer: PeerId, req: http.IncomingMessage, res: http.ServerResponse) => void): http.RequestListener { - return (req: http.IncomingMessage, res: http.ServerResponse): void => { - Promise.resolve() - .then(async () => { - const authResp = await this.authenticateRequest(req.headers.host ?? '', req.headers.authorization) - - for (const [key, value] of Object.entries(authResp.headers ?? {})) { - res.setHeader(key, value) - } - - if (authResp.status !== 200 || authResp.peer === undefined) { - res.statusCode = authResp.status - res.end() - - return - } - - httpAuthedHandler(authResp.peer, req, res) - }) - .catch(err => { - this.logger?.error('error handling request - %e', err) - }) - } - } - - /* eslint-disable-next-line complexity */ - private async authenticateRequest (hostname: string, authHeader?: string): Promise { - if (!this.validHostname(hostname)) { - return { status: 400 } - } - - if (authHeader === null || authHeader === undefined || authHeader === '') { - return this.returnChallenge(hostname, null, {}) - } - - const authFields = parseHeader(authHeader) - if (authFields.bearer !== undefined && authFields.bearer !== '') { - const peer = await this.unwrapBearerToken(hostname, authFields.bearer) - return { status: 200, peer } - } - - let opaqueState: OpaqueUnwrapped | null = null - if (authFields.opaque !== undefined) { - try { - const opaque = await this.unwrapOpaque(authFields.opaque) - if (opaque.hostname !== hostname) { - this.logger?.error('Invalid hostname') - return { status: 400 } - } - if (Date.now() - opaque.creationTime > this.tokenTTL) { - this.logger?.error('Token expired') - return { status: 400 } - } - - opaqueState = opaque - } catch (e) { - this.logger?.error('Invalid opaque') - return { status: 400 } - } - } - - let clientPublicKey: PublicKey | null = null - if (opaqueState?.clientPublicKey !== undefined) { - clientPublicKey = publicKeyFromProtobuf(uint8ArrayFromString(opaqueState.clientPublicKey, 'base64urlpad')) - } else if (authFields['public-key'] !== undefined) { - clientPublicKey = publicKeyFromProtobuf(uint8ArrayFromString(authFields['public-key'], 'base64urlpad')) - } - - const returnParams: Record = {} - let clientPeerId: PeerId | undefined - if (authFields.sig !== undefined) { - // Verify signature - if (clientPublicKey === null) { - this.logger?.error('Missing public-key') - return { status: 400 } - } - if (opaqueState?.challengeClient === null) { - this.logger?.error('Missing challenge-client') - return { status: 400 } - } - - const valid = await verify(clientPublicKey, PeerIDAuthScheme, [ - ['challenge-client', opaqueState?.challengeClient ?? ''], - ['hostname', hostname], - ['server-public-key', publicKeyToProtobuf(this.key.publicKey)] - ], uint8ArrayFromString(authFields.sig, 'base64urlpad')) - if (!valid) { - this.logger?.error('Invalid signature') - return { status: 400 } - } - - // Return a bearer token - clientPeerId = peerIdFromPublicKey(clientPublicKey) - returnParams.bearer = this.genBearerToken(clientPeerId, hostname) - } - - if (authFields['challenge-server'] !== undefined) { - if (clientPublicKey === null) { - this.logger?.error('Missing public-key') - return { status: 400 } - } - - // Sign and return challenge - const sig = await sign(this.key, PeerIDAuthScheme, [ - ['hostname', hostname], - ['client-public-key', publicKeyToProtobuf(clientPublicKey)], - ['challenge-server', authFields['challenge-server']] - ]) - returnParams['public-key'] = uint8ArrayToString(publicKeyToProtobuf(this.key.publicKey), 'base64urlpad') - returnParams.sig = uint8ArrayToString(sig, 'base64urlpad') - } - - if (returnParams.bearer !== undefined) { - return { status: 200, peer: clientPeerId, headers: { 'Authentication-info': encodeAuthParams(returnParams) } } - } else { - // Not authenticated - return this.returnChallenge(hostname, clientPublicKey, returnParams) - } - } - - private readHostname (req: Request): string { - const url = new URL(req.url) - let hostname = url.hostname - if (url.port === '' || url.port === undefined) { - return hostname - } - if (url.protocol === 'http:' && url.port !== '80') { - hostname += ':' + url.port - } - if (url.protocol === 'https:' && url.port !== '443') { - hostname += ':' + url.port - } - if (hostname === '') { - throw new Error('No hostname') - } - return hostname - } - - private async returnChallenge (hostname: string, clientPublicKey: PublicKey | null, returnParams: Record): Promise { - const challenge = this.generateChallenge() - returnParams['challenge-client'] = challenge - - returnParams.opaque = this.genOpaque({ - challengeClient: challenge, - clientPublicKey: clientPublicKey !== null ? uint8ArrayToString(publicKeyToProtobuf(clientPublicKey), 'base64urlpad') : undefined, - hostname, - creationTime: Date.now() - }) - return { status: 401, headers: { 'WWW-Authenticate': encodeAuthParams(returnParams) } } - } - - private genBearerToken (clientPeerId: PeerId, hostname: string): string { - return this.signBox(this.key, { - peer: clientPeerId.toString(), - h: hostname, - t: Date.now() - }) - } - - private async unwrapBearerToken (expectedHostname: string, token: string): Promise { - if (token.length < PeerIDAuthScheme.length + 1) { - throw new Error('Invalid bearer token') - } - const bearer = parseHeader(token).bearer - const unwrapped = await this.verifyBox(this.key.publicKey, bearer) as any - if (typeof unwrapped.peer !== 'string' || typeof unwrapped.h !== 'string' || typeof unwrapped.t !== 'number') { - throw new Error('Invalid bearer token') - } - if (unwrapped.h !== expectedHostname) { - throw new Error('Invalid hostname') - } - if (Date.now() - unwrapped.t > this.tokenTTL) { - throw new Error('Token expired') - } - return peerIdFromString(unwrapped.peer) - } - - private genOpaque (unwrapped: OpaqueUnwrapped): string { - return this.signBox(this.key, unwrapped) - } - - private async unwrapOpaque (opaque: string): Promise { - const unwrapped = await this.verifyBox(this.key.publicKey, opaque) as any - if (typeof unwrapped.challengeClient !== 'string' || typeof unwrapped.hostname !== 'string' || typeof unwrapped.creationTime !== 'number') { - throw new Error('Invalid opaque') - } - return unwrapped - } - - private signBox (key: PrivateKey, data: unknown): string { - const dataSerialized = JSON.stringify(data) - const dataBytes = textEncoder.encode(dataSerialized) - const sig = key.sign(dataBytes) - const jsonStr = JSON.stringify({ - val: uint8ArrayToString(dataBytes, 'base64urlpad'), - sig: uint8ArrayToString(sig, 'base64urlpad') - }) - return uint8ArrayToString(textEncoder.encode(jsonStr), 'base64urlpad') - } - - private async verifyBox (key: PublicKey, data: string): Promise { - const { sig, val } = JSON.parse(textDecoder.decode(uint8ArrayFromString(data, 'base64urlpad'))) - const valBytes = uint8ArrayFromString(val, 'base64urlpad') - const sigValid = await key.verify(valBytes, uint8ArrayFromString(sig, 'base64urlpad')) - if (!sigValid) { - throw new Error('Invalid signature') - } - const valStr = textDecoder.decode(valBytes) - return JSON.parse(valStr) - } - - private generateChallenge (): string { - const randomBytes = new Uint8Array(32) - crypto.getRandomValues(randomBytes) - return uint8ArrayToString(randomBytes, 'base64urlpad') - } -} - -interface OpaqueUnwrapped { - challengeClient: string - clientPublicKey?: string - hostname: string - creationTime: number -} - -const textEncoder = new TextEncoder() -const textDecoder = new TextDecoder() - -interface AuthenticationResponse { - status: number - headers?: Record - peer?: PeerId | undefined -} diff --git a/src/constants.ts b/src/constants.ts deleted file mode 100644 index 696da07..0000000 --- a/src/constants.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const PROTOCOL_NAME = '/http/1.1' -export const WELL_KNOWN_PROTOCOLS = '/.well-known/libp2p/protocols' diff --git a/src/fetch/index.ts b/src/fetch/index.ts deleted file mode 100644 index 168d963..0000000 --- a/src/fetch/index.ts +++ /dev/null @@ -1,409 +0,0 @@ -/* eslint-disable max-depth */ -/* eslint-disable complexity */ - -import { HTTPParser } from '@achingbrain/http-parser-js' -import { multiaddr, protocols } from '@multiformats/multiaddr' -import { multiaddrToUri } from '@multiformats/multiaddr-to-uri' -import defer from 'p-defer' -import { type Uint8ArrayList } from 'uint8arraylist' - -interface Fetch { (req: Request): Promise } - -const METHODS = [ - 'DELETE', - 'GET', - 'HEAD', - 'POST', - 'PUT', - 'CONNECT', - 'OPTIONS', - 'TRACE', - 'COPY', - 'LOCK', - 'MKCOL', - 'MOVE', - 'PROPFIND', - 'PROPPATCH', - 'SEARCH', - 'UNLOCK', - 'BIND', - 'REBIND', - 'UNBIND', - 'ACL', - 'REPORT', - 'MKACTIVITY', - 'CHECKOUT', - 'MERGE', - 'M-SEARCH', - 'NOTIFY', - 'SUBSCRIBE', - 'UNSUBSCRIBE', - 'PATCH', - 'PURGE', - 'MKCALENDAR', - 'LINK', - 'UNLINK' -] - -function getStringMethod (method: number): string { - return METHODS[method] ?? 'UNKNOWN' -} - -interface Duplex> { - source: AsyncIterable | Iterable - sink(source: AsyncIterable | Iterable): RSink -} - -let ranDetectionForBrokenReqBody = false -let brokenRequestBody = false - -/** - * Detects if the request body can not be a ReadableStream and should be read in - * full before returning the request This is only an issue in the current version of Firefox. - * - * @returns true if the request body can not be a ReadableStream and should be read in full before returning the request - */ -async function detectBrokenRequestBody (): Promise { - if (ranDetectionForBrokenReqBody) { - return brokenRequestBody - } - ranDetectionForBrokenReqBody = true - const rs = new ReadableStream({ - start (controller) { - controller.enqueue(new Uint8Array([0])) - controller.close() - } - }) - - const req = new Request('https://example.com', { - method: 'POST', - body: rs, - // @ts-expect-error this is required by NodeJS despite being the only reasonable option https://fetch.spec.whatwg.org/#requestinit - duplex: 'half' - }) - - const ab = await req.arrayBuffer() - brokenRequestBody = ab.byteLength !== 1 - return brokenRequestBody -} - -/** - * Create a fetch function that can be used to fetch requests via a duplex stream - * - * @returns a function that can be used to fetch requests via a duplex stream - */ -export function fetchViaDuplex (s: Duplex): Fetch { - return async (req) => { - await writeRequestToDuplex(s, req) - const [respP] = readHTTPMsg(false, s) - const resp = await respP - if (!(resp instanceof Response)) { - throw new Error('Expected a response') - } - return resp - } -} - -/** - * A function that can be used to handle HTTP requests - */ -export interface HTTPHandler { (req: Request): Promise } - -/** - * - * @param s - Duplex where the request will be read from and the response will be written to - * @param h - HTTP handler that will be called with the request - */ -export async function handleRequestViaDuplex (s: Duplex, h: HTTPHandler): Promise { - const [reqP] = readHTTPMsg(true, s) - const req = await reqP - if (!(req instanceof Request)) { - throw new Error('Expected a request') - } - - const resp = await h(req) - await writeResponseToDuplex(s, resp) -} - -/** - * Exported for testing. - * - * @param expectRequest - is this a Request or a Response - * @param r - where to read from - * @returns two promises. The first is the parsed Request or Response. The second is a promise that resolves when the parsing is done. - */ -export function readHTTPMsg (expectRequest: boolean, r: Duplex): [Promise, Promise] { - const msgPromise = defer() - - return [ - msgPromise.promise, - (async () => { - const body = new TransformStream() - const writer = body.writable.getWriter() - let messageComplete = false - let fulfilledMsgPromise = false - - const parser = new HTTPParser(expectRequest ? 'REQUEST' : 'RESPONSE') - parser[HTTPParser.kOnHeadersComplete] = (info) => { - fulfilledMsgPromise = true - - // Handle the headers - const headers = new Headers() - - for (let i = 0; i < info.headers.length; i += 2) { - headers.set(info.headers[i], info.headers[i + 1]) - } - - let reqBody: ReadableStream | null = body.readable - - // Headers are parsed. We can return the response - try { - if (expectRequest) { - if (getStringMethod(info.method) === 'GET') { - reqBody = null - } - - const urlWithHost = `https://${headers.get('Host') ?? 'unknown_host._libp2p'}${info.url}` - detectBrokenRequestBody().then(async (broken) => { - let req: Request - if (!broken) { - req = new Request(urlWithHost, { - method: getStringMethod(info.method), - body: reqBody, - headers, - // @ts-expect-error this is required by NodeJS despite being the only reasonable option https://fetch.spec.whatwg.org/#requestinit - duplex: 'half' - }) - } else { - if (reqBody === null) { - req = new Request(urlWithHost, { - method: getStringMethod(info.method), - headers - }) - } else { - // Unfortunate workaround for a bug in Firefox's Request implementation. - // They don't support ReadableStream bodies, so we need to read the whole body. - const rdr = reqBody.getReader() - const parts = [] - while (true) { - const { done, value } = await rdr.read() - if (done) { - break - } - if (value !== undefined) { - parts.push(value) - } - } - const totalSize = parts.reduce((acc, part) => acc + part.byteLength, 0) - const body = new Uint8Array(totalSize) - for (let i = 0, offset = 0; i < parts.length; i++) { - body.set(parts[i], offset) - offset += parts[i].byteLength - } - req = new Request(urlWithHost, { - method: getStringMethod(info.method), - body, - headers - }) - } - } - msgPromise.resolve(req) - fulfilledMsgPromise = true - }).catch(err => { - msgPromise.reject(err) - }) - } else { - let respBody: ReadableStream | null = body.readable - if (info.statusCode === 204) { - respBody = null - } - const resp = new Response(respBody, { - headers, - status: info.statusCode, - statusText: info.statusMessage - }) - msgPromise.resolve(resp) - fulfilledMsgPromise = true - } - } catch (error) { - msgPromise.reject(error) - } - } - parser[HTTPParser.kOnBody] = (buf) => { - writer.write(buf) - .catch((err: Error) => { - msgPromise.reject(err) - }) - } - parser[HTTPParser.kOnMessageComplete] = () => { - messageComplete = true - writer.close() - .catch((err: Error) => { - msgPromise.reject(err) - }) - } - - // Consume data - for await (const chunks of r.source) { - const chunk = chunks.subarray() - parser.execute(chunk) - } - - parser.finish() - - if (!messageComplete) { - await writer.abort(new Error('Incomplete HTTP message')) - - if (!fulfilledMsgPromise) { - msgPromise.reject(new Error('Incomplete HTTP message')) - } - } - })() - ] -} - -const multiaddrURIPrefix = 'multiaddr:' -const CRLF = '\r\n' -const encodedCRLF = new TextEncoder().encode(CRLF) -const encodedFinalChunk = new TextEncoder().encode(`0${CRLF}${CRLF}`) -async function writeRequestToDuplex (s: Duplex, request: Request): Promise { - const method = request.method - - let reqUrl = request.url - let path = '' - let urlHost = '' - if (reqUrl.startsWith(multiaddrURIPrefix)) { - reqUrl = reqUrl.substring(multiaddrURIPrefix.length) - const ma = multiaddr(reqUrl) - // Find the http-path component - const [, httpPathVal] = ma.stringTuples().find(([code, value]) => - code === protocols('http-path').code - - ) ?? ['', ''] - path = decodeURIComponent(httpPathVal ?? '') - - try { - const maWithoutPath = ma.decapsulateCode(protocols('http-path').code) - const url = new URL(multiaddrToUri(maWithoutPath)) - urlHost = url.host - } catch {} - } else { - const url = new URL(reqUrl) - urlHost = url.host - path = (url.pathname ?? '') + (url.search ?? '') - } - const headers = request.headers - - if (!path.startsWith('/')) { - path = `/${path}` - } - let httpRequest = `${method} ${path} HTTP/1.1${CRLF}` - - // Add Host header if not present - if (!headers.has('Host') && urlHost !== '') { - httpRequest += `Host: ${urlHost}${CRLF}` - } - // Add connection close - if (!headers.has('Connection')) { - httpRequest += `Connection: close${CRLF}` - } - - headers.forEach((value, name) => { - httpRequest += `${name}: ${value}${CRLF}` - }) - - let reqBody = request.body - if (request.body === undefined && typeof request.arrayBuffer === 'function') { - const body = await request.arrayBuffer() - if (body.byteLength > 0) { - reqBody = new ReadableStream({ - start (controller) { - controller.enqueue(new Uint8Array(body)) - controller.close() - } - }) - } else { - reqBody = null - } - } - - const requestIncludesContentAndNeedsContentLength = reqBody !== null && !headers.has('Content-Length') && (method === 'POST' || method === 'PUT' || method === 'PATCH') - - if (requestIncludesContentAndNeedsContentLength) { - // If we don't have the content length, we need to use chunked encoding - httpRequest += `Transfer-Encoding: chunked${CRLF}` - } - httpRequest += CRLF - - void s.sink((async function * () { - const httpRequestBuffer = new TextEncoder().encode(httpRequest) - yield httpRequestBuffer - - if (reqBody === null || reqBody === undefined) { - return - } - - const reader = reqBody.getReader() - try { - while (true) { - const { done, value } = await reader.read() - // If the stream is done, break the loop - if (done) { - if (requestIncludesContentAndNeedsContentLength) { - yield encodedFinalChunk - } - break - } - - // add the chunk length - if (requestIncludesContentAndNeedsContentLength) { - const chunkLength = value.byteLength.toString(16) - const chunkLengthBuffer = new TextEncoder().encode(`${chunkLength}${CRLF}`) - yield chunkLengthBuffer - } - - yield value - - if (requestIncludesContentAndNeedsContentLength) { - yield encodedCRLF - } - } - } finally { - reader.releaseLock() - } - })()) -} - -async function writeResponseToDuplex (s: Duplex, resp: Response): Promise { - await s.sink((async function * () { - const textEncoder = new TextEncoder() - const status = resp.status - const reason = resp.statusText - const headers = resp.headers - - let httpRequest = `HTTP/1.1 ${status} ${reason}${CRLF}` - - // Add connection close - if (!headers.has('Connection')) { - httpRequest += `Connection: close${CRLF}` - } - - headers.forEach((value, name) => { - httpRequest += `${name}: ${value}${CRLF}` - }) - httpRequest += CRLF - - yield textEncoder.encode(httpRequest) - - if (resp.body !== null && resp.body !== undefined) { - const reader = resp.body.getReader() - while (true) { - const { done, value } = await reader.read() - if (done) { - break - } - yield value - } - } - })()) -} diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index a81e369..0000000 --- a/src/index.ts +++ /dev/null @@ -1,145 +0,0 @@ -/** - * @packageDocumentation - * - * {@link http} implements the WHATWG [Fetch - * api](https://fetch.spec.whatwg.org). It can be used as a drop in replacement - * for the browser's fetch function. It supports http, https, and multiaddr - * URIs. Use HTTP in p2p networks. - * - * @example - * - * See the `examples/` for full examples of how to use the HTTP service. - * - * ```typescript - * import { createLibp2p } from 'libp2p' - * import { http } from '@libp2p/http-fetch' - * - * const node = await createLibp2p({ - * // other options ... - * services: { - * http: http() - * } - * }) - * - * await node.start() - * - * // Make an http request to a libp2p peer - * let resp = await node.services.http.fetch('multiaddr:/dns4/localhost/tcp/1234') - * - * // Or a traditional HTTP request - * resp = await node.services.http.fetch('multiaddr:/dns4/example.com/tcp/443/tls/http') - * - * // And of course, you can use the fetch API as you normally would - * resp = await node.services.http.fetch('https://example.com') - * - * // This gives you the accessibility of the fetch API with the flexibility of - * // using a p2p network. - * ``` - */ - -import { WHATWGFetch, type ProtosMap } from './whatwg-fetch-service.js' -import type { ComponentLogger, PeerId } from '@libp2p/interface' -import type { ConnectionManager, Registrar } from '@libp2p/interface-internal' -import type { Multiaddr } from '@multiformats/multiaddr' - -export { WELL_KNOWN_PROTOCOLS } from './constants.js' - -/** - * HTTP service interface - */ -export interface HTTP { - /** - * Make a request in a similar way to globalThis.fetch - */ - fetch(request: RequestInfo, requestInit?: RequestInit): Promise - - /** - * Uses the peer's .well-known endpoint to find where it hosts a given - * protocol. - * - * Throws an error if the peer does not serve the protocol. - */ - prefixForProtocol (peer: PeerId | Multiaddr, protocol: string): Promise - - /** - * Get the .well-known protocols for a peer. - */ - getPeerMeta (peer: PeerId | Multiaddr): Promise - - /** - * Registers a handler for the given protocol on the given path. - * - * This is incompatible with a customHTTPHandler. - */ - handleHTTPProtocol (protocol: string, path: string, handler: (req: Request) => Promise): void -} - -/** - * - */ -export interface HTTPWithCustomHandler { - /** - * Will full a request to this peer's .well-known libp2p endpoint using - * information from the registerProtocol calls. - */ - serveWellKnownProtocols (req: Request): Promise - - /** - * Inform this service of a protocol that you support and where it can be - * found. - * - * This metadata will be served at the .well-known endpoint. - */ - registerProtocol(protocol: string, path: string): void -} - -export interface FetchComponents { - registrar: Registrar - connectionManager: ConnectionManager - logger: ComponentLogger -} - -/** - * Options to configure the HTTP service. - * - * Only required if you want to specify a custom fetch implementation or used to - * provide one if your environment does not have a global fetch. - */ -export interface HTTPInit { - /** - * Native Fetch implementation. Defaults to global fetch if available. If not - * available, it will throw an error. - */ - fetch?(request: Request): Promise -} - -export interface CustomHTTPHandlerInit { - /** - * Custom root HTTP handler for handling requests. If you set this you are in - * charge of fulfilling all HTTP requests including serving the libp2p - * well-known protocols (`.serverWellKnownProtocols` may be helpful). - * - * Most users should use the default handler. Which is used by calling - * `.handleHTTPProtocol`. - */ - customHTTPHandler(req: Request): Promise -} - -/** - * Create an HTTP service that provides a `fetch` implementation and a way to - * register custom HTTP handlers. - */ -export function http (init: HTTPInit = {}): (components: FetchComponents) => HTTP { - return (components) => new WHATWGFetch(components, init) -} - -/** - * Start an HTTP service with a custom HTTP handler that is responsible for - * handling all HTTP requests and routing appropriately. - * - * Most users should use the `http` function and register their own protocols - * with `.handleHTTPProtocol`. - */ -export function httpCustomServer (init: HTTPInit & CustomHTTPHandlerInit): (components: FetchComponents) => HTTP & HTTPWithCustomHandler { - return (components) => new WHATWGFetch(components, init) -} diff --git a/src/ping.ts b/src/ping.ts deleted file mode 100644 index 511872d..0000000 --- a/src/ping.ts +++ /dev/null @@ -1,64 +0,0 @@ -// http-ping implementation -import { isPeerId, type Libp2p, type PeerId } from '@libp2p/interface' -import { multiaddr, type Multiaddr } from '@multiformats/multiaddr' -import type { HTTP } from './index.js' - -const PING_SIZE = 32 -export const PING_PROTOCOL_ID = '/http-ping/1' - -/** - * Serve a ping request - * - * @param req - An HTTP Request object - * @returns a Response object - */ -export async function servePing (req: Request): Promise { - const buf = new Uint8Array(await req.arrayBuffer()) - if (buf.length !== PING_SIZE) { - return new Response(null, { status: 400 }) - } - return new Response( - buf, - { - headers: { - 'Content-Type': 'application/octet-stream', - 'Content-Length': `${PING_SIZE}` - } - } - ) -} - -/** - * Send a ping request to a peer - * - * @param node - a libp2p node - * @param peerIdOrMultiaddr - Target peer - */ -export async function sendPing (node: Libp2p<{ http: HTTP }>, peerIdOrMultiaddr: PeerId | Multiaddr): Promise { - const peerAddr: Multiaddr = isPeerId(peerIdOrMultiaddr) ? multiaddr(`/p2p/${peerIdOrMultiaddr.toString()}`) : peerIdOrMultiaddr - const buf = new Uint8Array(PING_SIZE) - // Fill buffer with random data - crypto.getRandomValues(buf) - const pingEndpoint = await node.services.http.prefixForProtocol(peerAddr, PING_PROTOCOL_ID) - const requestURL = 'multiaddr:' + peerAddr.encapsulate(`/http-path/${encodeURIComponent(pingEndpoint)}`).toString() - - const resp = await node.services.http.fetch(new Request(requestURL, { - method: 'POST', - headers: { - 'Content-Type': 'application/octet-stream', - 'Content-Length': `${PING_SIZE}` - }, - body: buf - })) - if (resp.status !== 200) { - throw new Error(`Unexpected status code: ${resp.status}`) - } - - const respBuf = new Uint8Array(await resp.arrayBuffer()) - if (respBuf.length !== PING_SIZE) { - throw new Error(`Unexpected response size: ${respBuf.length}`) - } - if (!buf.every((v, i) => v === respBuf[i])) { - throw new Error('Ping body mismatch') - } -} diff --git a/src/well-known-handler.ts b/src/well-known-handler.ts deleted file mode 100644 index 63c9bc6..0000000 --- a/src/well-known-handler.ts +++ /dev/null @@ -1,29 +0,0 @@ -export type ProtocolID = string -export { WELL_KNOWN_PROTOCOLS } from './constants.js' -export type ProtosMap = Record -export class WellKnownHandler { - private readonly myWellKnownProtos: ProtosMap = {} - public async handleRequest (request: Request): Promise { - return new Response(JSON.stringify(this.myWellKnownProtos), { - headers: { - 'Content-Type': 'application/json' - } - }) - } - - // Register a protocol with a path and remember it so we can tell our peers - // about it via .well-known - public registerProtocol (protocol: string, path: string): void { - if (path === '') { - path = '/' - } - if (!path.startsWith('/')) { - path = `/${path}` - } - - if (this.myWellKnownProtos[protocol] != null) { - throw new Error(`Protocol ${protocol} already registered`) - } - this.myWellKnownProtos[protocol] = { path } - } -} diff --git a/src/whatwg-fetch-service.ts b/src/whatwg-fetch-service.ts deleted file mode 100644 index aec0c0d..0000000 --- a/src/whatwg-fetch-service.ts +++ /dev/null @@ -1,265 +0,0 @@ -import { isPeerId, type Logger, type PeerId, type Startable } from '@libp2p/interface' -import { multiaddr, protocols, type Multiaddr } from '@multiformats/multiaddr' -import { multiaddrToUri } from '@multiformats/multiaddr-to-uri' -import { PROTOCOL_NAME, WELL_KNOWN_PROTOCOLS } from './constants.js' -import { fetchViaDuplex, handleRequestViaDuplex, type HTTPHandler } from './fetch/index.js' -import { WellKnownHandler, type ProtosMap } from './well-known-handler.js' -import type { CustomHTTPHandlerInit, FetchComponents, HTTPInit, HTTP as WHATWGFetchInterface } from './index.js' -import type { IncomingStreamData } from '@libp2p/interface-internal' - -export type { ProtosMap } from './well-known-handler.js' - -const multiaddrURIPrefix = 'multiaddr:' - -type ProtocolID = string -type ProtoHandlers = Record - -export class WHATWGFetch implements Startable, WHATWGFetchInterface { - private readonly log: Logger - public readonly protocol: string = PROTOCOL_NAME - private readonly components: FetchComponents - private started: boolean - private readonly _fetch: (request: Request) => Promise - private readonly customHTTPHandler?: (request: Request) => Promise - private readonly wellKnownProtosCache = new LRUCache(100) - private readonly wellKnownHandler = new WellKnownHandler() - // Used when matching paths to protocols. We match from most specific to least specific. - private readonly myProtosSortedByLength: Array<{ proto: ProtocolID, path: string }> = [] - private readonly protoHandlers: ProtoHandlers = {} - - _hasCustomHandler (h: HTTPInit | CustomHTTPHandlerInit): h is CustomHTTPHandlerInit { - return (h as CustomHTTPHandlerInit).customHTTPHandler !== undefined - } - - constructor (components: FetchComponents, init: HTTPInit | (HTTPInit & CustomHTTPHandlerInit)) { - this.components = components - this.log = components.logger.forComponent('libp2p:http-fetch') - this.started = false - if (init.fetch != null) { - this._fetch = init.fetch - } else if (typeof globalThis.fetch === 'function') { - this._fetch = globalThis.fetch - } else { - throw new Error('No fetch implementation provided and global fetch is not available') - } - - if (this._hasCustomHandler(init)) { - this.customHTTPHandler = init.customHTTPHandler - } - } - - async start (): Promise { - await this.components.registrar.handle(this.protocol, (data: IncomingStreamData) => { - void this.handleMessage(data).catch((err) => { - this.log.error('error handling perf protocol message', err) - }) - }, {}) - this.started = true - } - - async stop (): Promise { - await this.components.registrar.unhandle(this.protocol) - this.started = false - } - - isStarted (): boolean { - return this.started - } - - private async handleMessage (data: IncomingStreamData): Promise { - const { stream } = data - try { - if (this.customHTTPHandler != null) { - await handleRequestViaDuplex(stream, this.customHTTPHandler) - return - } - await handleRequestViaDuplex(stream, this.defaultMuxer.bind(this)) - } catch (err) { - this.log.error('Error handling message', err) - } - } - - private async defaultMuxer (req: Request): Promise { - try { - const url = new URL(req.url) - if (url.pathname === WELL_KNOWN_PROTOCOLS) { - return await this.serveWellKnownProtocols(req) - } - for (const p of this.myProtosSortedByLength) { - if (url.pathname.startsWith(p.path)) { - const handler = this.protoHandlers[p.proto] - if (handler != null) { - return await handler(req) - } - } - } - - // No handler found, 404 - return new Response(null, { status: 404 }) - } catch (err) { - this.log.error('Error in defaultMuxer', err) - return new Response(null, { status: 500 }) - } - } - - async serveWellKnownProtocols (req: Request): Promise { - return this.wellKnownHandler.handleRequest(req) - } - - async fetch (request: string | Request, requestInit?: RequestInit): Promise { - if (typeof request === 'string') { - return this.innerFetch(new Request(request, requestInit ?? {})) - } - return this.innerFetch(request) - } - - private async innerFetch (request: Request): Promise { - // Get the peer from the request - const { url } = request - if (url.startsWith(multiaddrURIPrefix)) { - const ma = multiaddr(url.substring(multiaddrURIPrefix.length)) - const peerWithoutHTTPPath = ma.decapsulateCode(protocols('http-path').code) - - if (this.isHTTPTransportMultiaddr(peerWithoutHTTPPath)) { - if (peerWithoutHTTPPath.getPeerId() !== null) { - throw new Error('HTTP Transport does not yet support peer IDs. Use a stream based transport instead.') - } - const [, httpPathVal] = ma.stringTuples().find(([code]) => - code === protocols('http-path').code - ) ?? ['', ''] - let path = decodeURIComponent(httpPathVal ?? '') - if (!path.startsWith('/')) { - path = `/${path}` - } - const reqUrl = `${multiaddrToUri(peerWithoutHTTPPath)}${path}` - // We want to make a request over native fetch, so we need to copy the - // request and change the URL to be an HTTP URI - return this._fetch(new Request(reqUrl, { - body: request.body, - // @ts-expect-error - TS doesn't know about this property - duplex: request.duplex ?? 'half', - headers: request.headers, - cache: request.cache, - credentials: request.credentials, - integrity: request.integrity, - keepalive: request.keepalive, - method: request.method, - mode: request.mode, - redirect: request.redirect, - referrer: request.referrer, - referrerPolicy: request.referrerPolicy, - signal: request.signal - })) - } else { - const conn = await this.components.connectionManager.openConnection(peerWithoutHTTPPath) - - const s = await conn.newStream(PROTOCOL_NAME) - return fetchViaDuplex(s)(request) - } - } - // Use browser fetch or polyfill... - return this._fetch(request) - } - - private isHTTPTransportMultiaddr (peer: Multiaddr): boolean { - const parts = peer.protos() - if (parts.length === 0) { - throw new Error('peer multiaddr must have at least one part') - } - - // Reverse order for faster common case (/http is near the end) - for (let i = parts.length - 1; i >= 0; i--) { - if (parts[i].name === 'http' || parts[i].name === 'https') { - return true - } - } - return false - } - - // Register a protocol with a path and remember it so we can tell our peers - // about it via .well-known - registerProtocol (protocol: string, path: string): void { - if (path === '') { - path = '/' - } - if (!path.startsWith('/')) { - path = `/${path}` - } - this.wellKnownHandler.registerProtocol(protocol, path) - this.myProtosSortedByLength.push({ proto: protocol, path }) - this.myProtosSortedByLength.sort(({ path: a }, { path: b }) => b.length - a.length) - } - - handleHTTPProtocol (protocol: ProtocolID, path: string, handler: (req: Request) => Promise): void { - this.registerProtocol(protocol, path) - this.protoHandlers[protocol] = handler - } - - async getPeerMeta (peerOrMultiaddr: PeerId | Multiaddr): Promise { - const peerAddr: Multiaddr = isPeerId(peerOrMultiaddr) ? multiaddr(`/p2p/${peerOrMultiaddr.toString()}`) : peerOrMultiaddr - let cacheKey = peerAddr - - if (!isPeerId(peerOrMultiaddr)) { - const peerIdStr = peerAddr.getPeerId() - if (peerIdStr !== null) { - // If we have a peer ID, we should use it as the key, since the same peer can have multiple addresses - cacheKey = multiaddr(`/p2p/${peerIdStr}`) - } - } - - const cached = this.wellKnownProtosCache.get(cacheKey) - if (cached !== undefined) { - return cached - } - - const reqUrl = multiaddrURIPrefix + peerAddr.encapsulate(`/http-path/${encodeURIComponent(WELL_KNOWN_PROTOCOLS)}`).toString() - const resp = await this.fetch(new Request(reqUrl, { - method: 'GET', - headers: { - Accept: 'application/json' - } - })) - if (resp.status !== 200) { - throw new Error(`Unexpected status code: ${resp.status}`) - } - const peerMeta = await resp.json() - this.wellKnownProtosCache.set(cacheKey, peerMeta) - return peerMeta - } - - async prefixForProtocol (peer: PeerId | Multiaddr, protocol: string): Promise { - const peerMeta = await this.getPeerMeta(peer) - if (peerMeta[protocol] == null) { - throw new Error(`Peer does not serve protocol: ${protocol}`) - } - return peerMeta[protocol].path - } -} - -class LRUCache { - private readonly size: number - private readonly cache: Map - constructor (size: number) { - this.size = size - this.cache = new Map() - } - - get (key: K): V | undefined { - const v = this.cache.get(key) - if (v != null) { - // Move to front - this.cache.delete(key) - this.cache.set(key, v) - } - return v - } - - set (key: K, value: V): void { - if (this.cache.has(key)) { - this.cache.delete(key) - } else if (this.cache.size >= this.size) { - this.cache.delete(this.cache.keys().next().value) - } - this.cache.set(key, value) - } -} diff --git a/test/auth/index.spec.ts b/test/auth/index.spec.ts deleted file mode 100644 index 37ab4f6..0000000 --- a/test/auth/index.spec.ts +++ /dev/null @@ -1,103 +0,0 @@ -/* eslint-env mocha */ -import { generateKeyPair, privateKeyFromProtobuf } from '@libp2p/crypto/keys' -import { peerIdFromPrivateKey } from '@libp2p/peer-id' -import { expect } from 'aegir/chai' -import { toString as uint8ArrayToString, fromString as uint8ArrayFromString } from 'uint8arrays' -import { ClientAuth } from '../../src/auth/client.js' -import { PeerIDAuthScheme, sign } from '../../src/auth/common.js' -import { ServerAuth } from '../../src/auth/server.js' -import type { PeerId, PrivateKey } from '@libp2p/interface' - -describe('HTTP Peer ID Authentication', () => { - let init = false - let clientKey: PrivateKey - let serverKey: PrivateKey - let server: PeerId - beforeEach(async () => { - if (!init) { - init = true - clientKey = await generateKeyPair('Ed25519') - serverKey = await generateKeyPair('Ed25519') - server = peerIdFromPrivateKey(serverKey) - } - }) - - it('Should mutually authenticate', async () => { - const clientAuth = new ClientAuth(clientKey) - const serverAuth = new ServerAuth(serverKey, h => h === 'example.com') - - const fetch = async (input: string | URL | Request, init?: RequestInit): Promise => { - const req = new Request(input, init) - const resp = await serverAuth.httpHandler(req) - return resp - } - - const observedServerPeerId = await clientAuth.authenticateServer('https://example.com/auth', { - fetch - }) - expect(observedServerPeerId.equals(server)).to.be.true() - }) - - it('Should mutually authenticate with a custom port', async () => { - const clientAuth = new ClientAuth(clientKey) - const serverAuth = new ServerAuth(serverKey, h => h === 'foobar:12345') - - const fetch = async (input: string | URL | Request, init?: RequestInit): Promise => { - const req = new Request(input, init) - const resp = await serverAuth.httpHandler(req) - return resp - } - - const observedServerPeerId = await clientAuth.authenticateServer('https://foobar:12345/auth', { - fetch - }) - expect(observedServerPeerId.equals(server)).to.be.true() - }) - - it('Should time out when authenticating', async () => { - const clientAuth = new ClientAuth(clientKey) - - const controller = new AbortController() - controller.abort() - - await expect(clientAuth.authenticateServer('https://example.com/auth', { - signal: controller.signal - })).to.eventually.be.rejected - .with.property('name', 'AbortError') - }) - - it('Should sent request body to authenticated server', async () => { - const clientAuth = new ClientAuth(clientKey) - const serverAuth = new ServerAuth(serverKey, h => h === 'example.com') - - const echoHandler = async (req: Request): Promise => { - return new Response(await req.text()) - } - const httpHandler = serverAuth.withAuth(async (clientId, req) => { return echoHandler(req) }) - - const fetch = async (input: string | URL | Request, init?: RequestInit): Promise => { - const req = new Request(input, init) - return httpHandler(req) - } - - const expectedBody = 'Only for authenticated servers!' - const response = await clientAuth.authenticatedFetch('https://example.com/auth', { method: 'POST', body: expectedBody, verifyPeer: (observedId) => observedId.equals(server), fetch }) - - expect((await response.text())).to.be.equal(expectedBody) - expect(response.peer.equals(server)).to.be.true() - }) - - it('Should match the test vectors', async () => { - const clientKeyHex = '080112208139770ea87d175f56a35466c34c7ecccb8d8a91b4ee37a25df60f5b8fc9b394' - const serverKeyHex = '0801124001010101010101010101010101010101010101010101010101010101010101018a88e3dd7409f195fd52db2d3cba5d72ca6709bf1d94121bf3748801b40f6f5c' - const clientPubKeyEncoded = uint8ArrayFromString(clientKeyHex, 'base16') - const serverKey = privateKeyFromProtobuf(uint8ArrayFromString(serverKeyHex, 'base16')) - - const serverSig = await sign(serverKey, PeerIDAuthScheme, [ - ['challenge-server', 'ERERERERERERERERERERERERERERERERERERERERERE='], - ['client-public-key', clientPubKeyEncoded], - ['hostname', 'example.com'] - ]) - expect(uint8ArrayToString(serverSig, 'base64urlpad')).to.equal('UA88qZbLUzmAxrD9KECbDCgSKAUBAvBHrOCF2X0uPLR1uUCF7qGfLPc7dw3Olo-LaFCDpk5sXN7TkLWPVvuXAA==') - }) -}) diff --git a/test/fetch/index.spec.ts b/test/fetch/index.spec.ts deleted file mode 100644 index 22fb400..0000000 --- a/test/fetch/index.spec.ts +++ /dev/null @@ -1,212 +0,0 @@ -/* eslint-disable no-console */ -/* eslint-env mocha */ - -import { expect } from 'aegir/chai' -import { duplexPair } from 'it-pair/duplex' -import { type Uint8ArrayList, isUint8ArrayList } from 'uint8arraylist' -import { fetchViaDuplex, handleRequestViaDuplex } from '../../src/fetch/index.js' -import { cases } from './cases/cases.js' - -describe('Roundtrips', () => { - it('handles a simple GET request', async () => { - const [client, server] = duplexPair() - - const serverHandler = handleRequestViaDuplex(server, async (req) => { - console.log('Got request', req) - return new Response('Hello World') - }).catch((err) => { - console.error('Error handling request', err) - throw err - }) - - const resp = await fetchViaDuplex(client)(new Request('https://example.com/')) - expect(await resp.text()).to.equal('Hello World') - - // Assert we didn't fail here - await serverHandler - }) -}) - -describe('Make a fetch request via duplex', () => { - it('A simple GET request', async () => { - const [client, server] = duplexPair() - const respPromise = fetchViaDuplex(client)(new Request('http://example.com/')) - - let reqToServer = '' - const decoder = new TextDecoder() - for await (const chunk of server.source) { - if (isUint8ArrayList(chunk)) { - throw new Error('Should not be a Uint8ArrayList') - } - reqToServer += decoder.decode(chunk) - } - - console.log(reqToServer) - expect(reqToServer).to.equal('GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n') - - void server.sink((async function * () { - yield new TextEncoder().encode('HTTP/1.1 200 OK\r\n\r\n') - })()) - const resp = await respPromise - expect(resp.status).to.equal(200) - }) - - it('A simple GET request with headers', async () => { - const [client, server] = duplexPair() - const respPromise = fetchViaDuplex(client)(new Request('http://example.com/', { headers: { 'X-Test': 'foo' } })) - - let reqToServer = '' - const decoder = new TextDecoder() - for await (const chunk of server.source) { - if (isUint8ArrayList(chunk)) { - throw new Error('Should not be a Uint8ArrayList') - } - reqToServer += decoder.decode(chunk) - } - - expect(reqToServer).to.equal('GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\nx-test: foo\r\n\r\n') - - void server.sink((async function * () { - yield new TextEncoder().encode('HTTP/1.1 200 OK\r\nX-test: bar\r\n\r\n') - })()) - const resp = await respPromise - expect(resp.status).to.equal(200) - expect(resp.headers.get('x-test')).to.equal('bar') - }) - - it('Post some data', async () => { - const [client, server] = duplexPair() - const respPromise = fetchViaDuplex(client)(new Request('http://example.com/?foo=bar', { method: 'POST', headers: { 'X-Test': 'foo' }, body: 'hello world' })) - - let reqToServer = '' - const decoder = new TextDecoder() - for await (const chunk of server.source) { - if (isUint8ArrayList(chunk)) { - throw new Error('Should not be a Uint8ArrayList') - } - reqToServer += decoder.decode(chunk) - } - - console.log(reqToServer) - expect(reqToServer).to.equal('POST /?foo=bar HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\ncontent-type: text/plain;charset=UTF-8\r\nx-test: foo\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nhello world\r\n0\r\n\r\n') - - void server.sink((async function * () { - yield new TextEncoder().encode('HTTP/1.1 200 OK\r\nX-test: bar\r\n\r\nbaz') - })()) - const resp = await respPromise - expect(resp.status).to.equal(200) - expect(resp.headers.get('x-test')).to.equal('bar') - expect(await resp.text()).to.equal('baz') - }) - - it('Handles trash', async () => { - const [client, server] = duplexPair() - const respPromise = fetchViaDuplex(client)(new Request('http://example.com/')) - - let reqToServer = '' - const decoder = new TextDecoder() - for await (const chunk of server.source) { - if (isUint8ArrayList(chunk)) { - throw new Error('Should not be a Uint8ArrayList') - } - reqToServer += decoder.decode(chunk) - } - - expect(reqToServer).to.equal('GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n') - - void server.sink((async function * () { - yield new TextEncoder().encode('FOOOOOOOOOOOOOOOOo') - })()) - await expect(respPromise).to.eventually.be.rejected() - }) - - it('Message comes in a trickle', async () => { - for (const httpCase of cases.filter(c => c.type === 'RESPONSE' && c.mayFail !== true)) { - const expectedStatusCode = httpCase.statusCode - if (expectedStatusCode === undefined || expectedStatusCode === null) { - continue - } - if (expectedStatusCode < 200 || expectedStatusCode >= 600) { - // Response object doesn't parse these - continue - } - if (httpCase?.httpMajor !== 1 || httpCase?.httpMinor !== 1) { - // We don't use anything but HTTP/1.1 - continue - } - const [client, server] = duplexPair() - // Request doesn't matter - const respPromise = fetchViaDuplex(client)(new Request('http://example.com/')) - - let reqToServer = '' - const decoder = new TextDecoder() - for await (const chunk of server.source) { - if (isUint8ArrayList(chunk)) { - throw new Error('Should not be a Uint8ArrayList') - } - reqToServer += decoder.decode(chunk) - } - expect(reqToServer).to.equal('GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n') - - void server.sink((async function * () { - const rawHttp = new TextEncoder().encode(httpCase.raw) - // Trickle the response 1 byte at a time - for (let i = 0; i < rawHttp.length; i++) { - yield rawHttp.subarray(i, i + 1) - } - })()) - const resp = await respPromise - - expect(resp.status).to.equal(expectedStatusCode) - const chunk = (arr: T[], size: number): T[][] => arr.reduce((chunks, el, i) => i % size === 0 ? [...chunks, [el]] : (chunks[chunks.length - 1].push(el), chunks), []) - for (const [key, value] of chunk(httpCase.headers, 2)) { - expect(resp.headers.get(key)).to.equal(value) - } - - expect(await resp.text()).to.equal(httpCase.body ?? '') - } - }) - - it('Parses all responses', async () => { - for (const httpCase of cases.filter(c => c.type === 'RESPONSE' && c.mayFail !== true)) { - const expectedStatusCode = httpCase.statusCode - if (expectedStatusCode === undefined || expectedStatusCode === null) { - continue - } - if (expectedStatusCode < 200 || expectedStatusCode >= 600) { - // Response object doesn't parse these - continue - } - if (httpCase?.httpMajor !== 1 || httpCase?.httpMinor !== 1) { - // We don't use anything but HTTP/1.1 - continue - } - const [client, server] = duplexPair() - // Request doesn't matter - const respPromise = fetchViaDuplex(client)(new Request('http://example.com/')) - - let reqToServer = '' - const decoder = new TextDecoder() - for await (const chunk of server.source) { - if (isUint8ArrayList(chunk)) { - throw new Error('Should not be a Uint8ArrayList') - } - reqToServer += decoder.decode(chunk) - } - expect(reqToServer).to.equal('GET / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n') - - void server.sink((async function * () { - yield new TextEncoder().encode(httpCase.raw) - })()) - const resp = await respPromise - - expect(resp.status).to.equal(expectedStatusCode) - const chunk = (arr: T[], size: number): T[][] => arr.reduce((chunks, el, i) => i % size === 0 ? [...chunks, [el]] : (chunks[chunks.length - 1].push(el), chunks), []) - for (const [key, value] of chunk(httpCase.headers, 2)) { - expect(resp.headers.get(key)).to.equal(value) - } - - expect(await resp.text()).to.equal(httpCase.body ?? '') - } - }) -}) diff --git a/test/index.spec.ts b/test/index.spec.ts deleted file mode 100644 index 9830e21..0000000 --- a/test/index.spec.ts +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-env mocha */ - -import { isPeerId, start, stop } from '@libp2p/interface' -import { streamPair } from '@libp2p/interface-compliance-tests/mocks' -import { defaultLogger } from '@libp2p/logger' -import { peerIdFromString } from '@libp2p/peer-id' -import { multiaddr, type Multiaddr } from '@multiformats/multiaddr' -import { expect } from 'aegir/chai' -import { duplexPair } from 'it-pair/duplex' -import { type Libp2p } from 'libp2p' -import pDefer from 'p-defer' -import { stubInterface, type StubbedInstance } from 'sinon-ts' -import { http, type HTTP } from '../src/index.js' -import * as ping from '../src/ping.js' -import type { ComponentLogger, Connection, PeerId, StreamHandler } from '@libp2p/interface' -import type { ConnectionManager, Registrar } from '@libp2p/interface-internal' - -interface StubbedHTTPComponents { - registrar: StubbedInstance - connectionManager: StubbedInstance - logger: ComponentLogger -} - -export function createComponents (): StubbedHTTPComponents { - return { - registrar: stubInterface(), - connectionManager: stubInterface(), - logger: defaultLogger() - } -} - -describe('whatwg-fetch', () => { - let serverComponents: StubbedHTTPComponents - let clientComponents: StubbedHTTPComponents - let server: HTTP - let client: HTTP - const serverPeerID: PeerId = peerIdFromString('12D3KooWJRSrypvnpHgc6ZAgyCni4KcSmbV7uGRaMw5LgMKT18fq') - const serverMultiaddr: Multiaddr = multiaddr('/ip4/1.2.3.4/tcp/1234' + '/p2p/' + serverPeerID.toString()) - - beforeEach(async () => { - serverComponents = createComponents() - clientComponents = createComponents() - await start(serverComponents) - await start(clientComponents) - - let serverCB: StreamHandler - const serverCBRegistered = pDefer() - serverComponents.registrar.handle.callsFake(async (protocol: string, cb: StreamHandler) => { - serverCB = cb - serverCBRegistered.resolve() - }) - - const conn = stubInterface() - conn.newStream.callsFake(async (protos: string | string[], options?: any) => { - const duplexes = duplexPair() - const streams = streamPair({ duplex: duplexes[0] }, { duplex: duplexes[1] }) - serverCB({ stream: streams[0], connection: conn }) - return streams[1] - }) - - clientComponents.connectionManager.openConnection.callsFake(async (peer: PeerId | Multiaddr | Multiaddr[]) => { - if (Array.isArray(peer)) { - peer = peer[0] - } - - if (isPeerId(peer) ? peer.equals(serverPeerID) : peer.getPeerId() === serverMultiaddr.getPeerId()) { - await serverCBRegistered.promise - return conn - } - throw new Error('Unexpected peer: ' + peer.toString()) - }) - - server = http()(serverComponents) - client = http()(clientComponents) - await start(client) - await start(server) - }) - - afterEach(async () => { - await stop(serverComponents) - await stop(clientComponents) - await stop(server) - await stop(client) - }) - - it('Standard ping roundtrip', async () => { - // Mount the ping handler on the server under /ping - server.handleHTTPProtocol(ping.PING_PROTOCOL_ID, '/ping', ping.servePing) - - const clientNode = stubInterface>({ services: { http: client } }) - - await ping.sendPing(clientNode, serverMultiaddr) - }) - - it('Standard ping roundtrip with peer id', async () => { - // Mount the ping handler on the server under /ping - server.handleHTTPProtocol(ping.PING_PROTOCOL_ID, '/ping', ping.servePing) - - const clientNode = stubInterface>({ services: { http: client } }) - - await ping.sendPing(clientNode, serverPeerID) - }) - - it('Throws an error if using an http transport with a peer id component', async () => { - const clientNode = stubInterface>({ services: { http: client } }) - - await expect(ping.sendPing(clientNode, multiaddr('/ip4/127.0.0.1/http/p2p/' + serverPeerID.toString()))).to.be.rejectedWith('HTTP Transport does not yet support peer IDs') - }) -}) diff --git a/test/node.ts b/test/node.ts deleted file mode 100644 index 7894ed5..0000000 --- a/test/node.ts +++ /dev/null @@ -1,99 +0,0 @@ -import http from 'node:http' -import { generateKeyPair } from '@libp2p/crypto/keys' -import { peerIdFromPrivateKey } from '@libp2p/peer-id' -import { expect } from 'aegir/chai' -import pDefer from 'p-defer' -import { ClientAuth, ServerAuth } from '../src/auth/index.js' -import type { PeerId, PrivateKey } from '@libp2p/interface' - -describe('@libp2p/http-fetch', () => { - describe('client auth', () => { - let clientKey: PrivateKey - let serverKey: PrivateKey - let server: http.Server - - beforeEach(async () => { - clientKey = await generateKeyPair('Ed25519') - serverKey = await generateKeyPair('Ed25519') - }) - - afterEach(async () => { - server?.close() - server?.closeAllConnections() - }) - - it('should perform auth from client', async () => { - const clientAuth = new ClientAuth(clientKey) - const serverAuth = new ServerAuth(serverKey, h => h.startsWith('127.0.0.1')) - const clientPeer = pDefer() - const echoListener = serverAuth.requestListener((clientId, req, res) => { - clientPeer.resolve(clientId) - req.pipe(res) - }) - - server = http.createServer(echoListener) - - const port = await new Promise((resolve, reject) => { - const listener = server.listen(0, () => { - const address = listener.address() - - if (address == null || typeof address === 'string') { - reject(new Error('Could not listen on port')) - return - } - - resolve(address.port) - }) - }) - - await expect(clientAuth.authenticateServer(`http://127.0.0.1:${port}`)).to.eventually.deep.equal(peerIdFromPrivateKey(serverKey)) - await expect(clientPeer.promise).to.eventually.deep.equal(peerIdFromPrivateKey(clientKey)) - }) - - it('should respect cookies during auth', async () => { - const clientAuth = new ClientAuth(clientKey) - const serverAuth = new ServerAuth(serverKey, h => h.startsWith('127.0.0.1')) - const cookie = pDefer() - const echoListener = serverAuth.requestListener((clientId, req, res) => { - req.pipe(res) - }) - const cookieName = 'test-cookie-name' - const cookieValue = 'test-cookie-value' - let requests = 0 - - server = http.createServer((req, res) => { - requests++ - - const cookieHeader = req.headers.cookie - - if (cookieHeader == null) { - if (requests === 2) { - cookie.reject(new Error('No cookie header found on second request')) - } - - res.setHeader('set-cookie', `${cookieName}=${cookieValue}; Expires=${new Date(Date.now() + 86_400_000).toString()}; HttpOnly`) - } else { - cookie.resolve(cookieHeader) - } - - echoListener(req, res) - }) - - const port = await new Promise((resolve, reject) => { - const listener = server.listen(0, () => { - const address = listener.address() - - if (address == null || typeof address === 'string') { - reject(new Error('Could not listen on port')) - return - } - - resolve(address.port) - }) - }) - - await expect(clientAuth.authenticateServer(`http://127.0.0.1:${port}`)).to.eventually.deep.equal(peerIdFromPrivateKey(serverKey)) - await expect(cookie.promise).to.eventually.equal(`${cookieName}=${cookieValue}`) - }) - }) -}) diff --git a/typedoc.json b/typedoc.json index 000b99f..d3ef748 100644 --- a/typedoc.json +++ b/typedoc.json @@ -1,8 +1,13 @@ { - "entryPoints": [ - "./src/index.ts", - "./src/auth/index.ts", - "./src/ping.ts", - "./src/well-known-handler.ts" + "$schema": "https://typedoc.org/schema.json", + "name": "@libp2p/http", + "readme": "./README.md", + "headings": { + "readme": false, + "document": false + }, + "exclude": [ + "examples/*", + "packages/interop" ] }